package com.onlineMIS.ORM.DAO.headQ.inventory;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

import net.sf.json.JSONObject;

import org.apache.commons.lang.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.formula.functions.Now;
import org.hibernate.Criteria;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.aop.ThrowsAdvice;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.onlineMIS.ORM.DAO.Response;
import com.onlineMIS.ORM.DAO.chainS.chainMgmt.ChainPriceIncrementDaoImpl;
import com.onlineMIS.ORM.DAO.chainS.inventoryFlow.ChainInOutStockDaoImpl;
import com.onlineMIS.ORM.DAO.chainS.sales.PurchaseService;
import com.onlineMIS.ORM.DAO.chainS.user.ChainStoreDaoImpl;
import com.onlineMIS.ORM.DAO.chainS.user.ChainStoreService;
import com.onlineMIS.ORM.DAO.headQ.SQLServer.BilldraftidxDAOImpl;
import com.onlineMIS.ORM.DAO.headQ.SQLServer.ClientDAOImpl;
import com.onlineMIS.ORM.DAO.headQ.SQLServer.ProductsMSDAOImpl;
import com.onlineMIS.ORM.DAO.headQ.SQLServer.RegionMSDAOImpl;
import com.onlineMIS.ORM.DAO.headQ.SQLServer.SalemanagebilldrfDAOImpl;
import com.onlineMIS.ORM.DAO.headQ.barCodeGentor.HeadQEntityTagDaoImpl;
import com.onlineMIS.ORM.DAO.headQ.barCodeGentor.HeadQTagDaoImpl;
import com.onlineMIS.ORM.DAO.headQ.barCodeGentor.HeadQTagGroupDaoImpl;
import com.onlineMIS.ORM.DAO.headQ.barCodeGentor.ProductBarcodeDaoImpl;
import com.onlineMIS.ORM.DAO.headQ.barCodeGentor.ProductBarcodePicDaoImpl;
import com.onlineMIS.ORM.DAO.headQ.barCodeGentor.ProductBarcodeService;
import com.onlineMIS.ORM.DAO.headQ.barCodeGentor.ProductDaoImpl;
import com.onlineMIS.ORM.DAO.headQ.custMgmt.HeadQCustDaoImpl;
import com.onlineMIS.ORM.DAO.headQ.finance.ChainAcctFlowDaoImpl;
import com.onlineMIS.ORM.DAO.headQ.inventoryFlow.HeadQInventoryStockDAOImpl;
import com.onlineMIS.ORM.DAO.headQ.inventoryFlow.HeadQInventoryStoreDAOImpl;
import com.onlineMIS.ORM.DAO.headQ.supplier.purchase.HeadqPurchaseHistoryDaoImpl;
import com.onlineMIS.ORM.DAO.headQ.supplier.purchase.PurchaseOrderDaoImpl;
import com.onlineMIS.ORM.DAO.headQ.supplier.purchase.SupplierPurchaseService;
import com.onlineMIS.ORM.DAO.headQ.user.NewsService;
import com.onlineMIS.ORM.DAO.headQ.user.UserInforService;
import com.onlineMIS.ORM.entity.chainS.chainMgmt.ChainPriceIncrement;
import com.onlineMIS.ORM.entity.chainS.inventoryFlow.ChainInOutStock;
import com.onlineMIS.ORM.entity.chainS.user.ChainRoleType;
import com.onlineMIS.ORM.entity.chainS.user.ChainStore;
import com.onlineMIS.ORM.entity.chainS.user.ChainUserInfor;
import com.onlineMIS.ORM.entity.headQ.SQLServer.Billdraftidx;
import com.onlineMIS.ORM.entity.headQ.SQLServer.ClientsMS;
import com.onlineMIS.ORM.entity.headQ.SQLServer.PriceMS;
import com.onlineMIS.ORM.entity.headQ.SQLServer.ProductsMS;
import com.onlineMIS.ORM.entity.headQ.SQLServer.RegionMS;
import com.onlineMIS.ORM.entity.headQ.SQLServer.Salemanagebilldrf;
import com.onlineMIS.ORM.entity.headQ.barcodeGentor.Brand;
import com.onlineMIS.ORM.entity.headQ.barcodeGentor.HeadQTag;
import com.onlineMIS.ORM.entity.headQ.barcodeGentor.HeadQTagGroup;
import com.onlineMIS.ORM.entity.headQ.barcodeGentor.HeadQTagVO;
import com.onlineMIS.ORM.entity.headQ.barcodeGentor.HeadqEntityTag;
import com.onlineMIS.ORM.entity.headQ.barcodeGentor.Product;
import com.onlineMIS.ORM.entity.headQ.barcodeGentor.ProductBarcodePic;
import com.onlineMIS.ORM.entity.headQ.barcodeGentor.ProductBarcode;
import com.onlineMIS.ORM.entity.headQ.custMgmt.HeadQCust;
import com.onlineMIS.ORM.entity.headQ.custMgmt.HeadQCustVO;
import com.onlineMIS.ORM.entity.headQ.finance.AllAccountsFlowTemplate;
import com.onlineMIS.ORM.entity.headQ.finance.ChainAcctFlow;
import com.onlineMIS.ORM.entity.headQ.finance.FinanceBillFlowDetailsVO;
import com.onlineMIS.ORM.entity.headQ.finance.HeadQAcctFlow;
import com.onlineMIS.ORM.entity.headQ.inventoryFlow.HeadQInventoryStock;
import com.onlineMIS.ORM.entity.headQ.inventoryFlow.HeadQInventoryStore;
import com.onlineMIS.ORM.entity.headQ.supplier.purchase.HeadqPurchaseHistory;
import com.onlineMIS.ORM.entity.headQ.supplier.purchase.PurchaseOrder;
import com.onlineMIS.ORM.entity.headQ.supplier.purchase.PurchaseOrderProduct;
import com.onlineMIS.ORM.entity.headQ.inventory.HeadQSalesHistory;
import com.onlineMIS.ORM.entity.headQ.inventory.HeadqInventoryPDAorderVO;
import com.onlineMIS.ORM.entity.headQ.inventory.HeadqInventoryPDAproductVO;
import com.onlineMIS.ORM.entity.headQ.inventory.ImgDetailsVO;
import com.onlineMIS.ORM.entity.headQ.inventory.InventoryOrder;
import com.onlineMIS.ORM.entity.headQ.inventory.InventoryOrderPrintVO;
import com.onlineMIS.ORM.entity.headQ.inventory.InventoryOrderProduct;
import com.onlineMIS.ORM.entity.headQ.inventory.InventoryOrderTagboxVO;
import com.onlineMIS.ORM.entity.headQ.inventory.InventoryOrderTemplate;
import com.onlineMIS.ORM.entity.headQ.inventory.InventoryOrderVO;
import com.onlineMIS.ORM.entity.headQ.inventory.JinSuanOrderTemplate;
import com.onlineMIS.ORM.entity.headQ.inventory.PDAOrderByBrandTemplate;
import com.onlineMIS.ORM.entity.headQ.inventory.PDAOrderTemplate;
import com.onlineMIS.ORM.entity.headQ.user.RoleFunctionality;
import com.onlineMIS.ORM.entity.headQ.user.UserFunctionalityDeleted;
import com.onlineMIS.ORM.entity.headQ.user.UserInfor;
import com.onlineMIS.action.headQ.inventory.InventoryOrderActionFormBean;
import com.onlineMIS.action.headQ.inventory.InventoryOrderActionUIBean;
import com.onlineMIS.action.headQ.ipad.IpadActionFormBean;
import com.onlineMIS.action.headQ.ipad.IpadActionUIBean;
import com.onlineMIS.action.headQ.ipad.IpadPdaOrderDetailsVO;
import com.onlineMIS.action.headQ.ipad.IpadPdaVO;
import com.onlineMIS.action.headQ.ipad.IpadPeiHuoVO;
import com.onlineMIS.common.Common_util;
import com.onlineMIS.common.ExcelUtil;
import com.onlineMIS.common.HttpUtil;
import com.onlineMIS.common.SessionInfo;
import com.onlineMIS.common.StrCheckUtils;
import com.onlineMIS.common.loggerLocal;
import com.onlineMIS.filter.SystemParm;
import com.onlineMIS.sorter.ChainStatisticReportItemVOSorter;
import com.onlineMIS.sorter.HeadQInventoryOrderProduct4Peihuo;
import com.onlineMIS.sorter.SortByBrandProductCode;
import com.opensymphony.xwork2.ActionContext;
import com.sun.org.apache.xerces.internal.util.Status;

import exception.QXMISException;

@Service
public class InventoryService {
	@Autowired
	private InventoryOrderProductDAOImpl inventoryOrderProductDAOImpl;
	@Autowired
	private HeadqPurchaseHistoryDaoImpl headqPurchaseHistoryDaoImpl;
	@Autowired
	private InventoryOrderDAOImpl inventoryOrderDAOImpl;
	@Autowired
	private BilldraftidxDAOImpl billdraftidxImpl;
	@Autowired
	private SalemanagebilldrfDAOImpl salemanagebilldrfImpl;
	@Autowired
	private ProductsMSDAOImpl productsMSImpl;
	@Autowired
	private HeadQSalesHisDAOImpl headQSalesHisDAOImpl;
	@Autowired
	private ProductBarcodeService ProductBarcodeService;
	@Autowired
	private HeadQInventoryStoreDAOImpl headQInventoryStoreDAOImpl;
	@Autowired
	private ClientDAOImpl clientDAOImpl;
	@Autowired
	private ProductBarcodeDaoImpl productBarcodeDaoImpl;
	@Autowired
	private UserInforService userInforService;
	@Autowired
	private ChainAcctFlowDaoImpl chainAcctFlowDaoImpl;
	@Autowired
	private ChainStoreDaoImpl chainStoreDaoImpl;
	@Autowired
	private ChainPriceIncrementDaoImpl chainPriceIncrementDaoImpl;
	@Autowired
	private HeadQCustDaoImpl headQCustDaoImpl;
	@Autowired
	private ClientDAOImpl clientImpl;
	@Autowired
	private RegionMSDAOImpl regionMSDAOImpl;
	@Autowired
	private HeadQInventoryStockDAOImpl headQInventoryStockDAOImpl;
	@Autowired
	protected ProductBarcodeService productService;
	@Autowired
	private HeadQTagDaoImpl headQTagDaoImpl;
	@Autowired
	private HeadQTagGroupDaoImpl tagGroupDaoImpl;
	@Autowired
	private HeadQEntityTagDaoImpl entityTagDaoImpl;

    @Autowired
	private PurchaseOrderDaoImpl PurchaseOrderDaoImpl;
    @Autowired
    private SupplierPurchaseService purchaseService;
	@Autowired
	private ProductBarcodePicDaoImpl picDaoImpl;
    
	/**
	 * 保存到精算之后，等待会计审核是否要导入条码系统
	 * 
	 * @param orderID
	 * @param userInfor
	 * @return
	 * @throws QXMISException
	 * @throws Exception
	 */
	@Transactional
	public Response saveToJinSuan(int orderID, UserInfor userInfor) throws Exception {
		Response response = new Response();
		loggerLocal.info("<---InventoryService.saveToJinSuan() : order ID" + orderID);

		InventoryOrder order = inventoryOrderDAOImpl.retrieveOrder(orderID);

		if (order == null) {
			response.setFail("无法找到单据 : " + orderID);
			return response;
		} else if (order.getOrder_Status() != InventoryOrder.STATUS_ACCOUNT_PROCESS
				&& order.getOrder_Status() != InventoryOrder.STATUS_WAITING_AUDIT) {
			response.setFail("单据状态(" + order.getOrder_Status_s() + "), 无法再次导入精算");
			return response;
		} else if (order.getImportTimes() > 0) {
			response.setFail("此单据导入精算次数(" + order.getImportTimes() + "), 无法再次导入精算");
			return response;
		}

		/**
		 * 第一步: 验证数据 is to validate the data
		 */
		String errorMessage = "";
		order.putSetToList();
		List<InventoryOrderProduct> products = order.getProduct_List();

		// Put barcodes in the list
		Set<String> barcodes = new HashSet<String>();
		for (InventoryOrderProduct product : products) {
			barcodes.add(product.getProductBarcode().getBarcode());
		}

		// get the serial numbers
		List<ProductBarcode> productBarcodes = productBarcodeDaoImpl.getProductBarcodes(barcodes);
		Set<String> serialNums = new HashSet<String>();
		for (ProductBarcode pb : productBarcodes) {
			serialNums.add(pb.getProduct().getSerialNum());
		}

		Map<String, ProductBarcode> productMap = productBarcodeDaoImpl.getProductMapByBarcode(barcodes);
		Map<String, ProductsMS> productMSMap = productsMSImpl.retrieveProducts(barcodes);
		for (String barcode : barcodes) {
			try {
				PriceMS priceMS = productMSMap.get(barcode).getPrice();
				ProductBarcode productBarcode = productMap.get(barcode);
				if (priceMS == null || productBarcode == null) {
					errorMessage += barcode + ",";
				}
			} catch (Exception e) {
				loggerLocal.error("InventoryService.saveToJinSua()，barcode : " + barcode + " can't be found");
				errorMessage += barcode + ",";
			}
		}

		if (errorMessage.length() != 0)
			errorMessage = "以下条码不存在精算中 : " + errorMessage + "<br/>";

		int jinsuanID = userInfor.getJinsuanID();
		if (jinsuanID == 0) {
			errorMessage += "用户不存在精算账户，请联系系统管理员" + "<br/>";
		}

		if (errorMessage.length() == 0) {
			// 重复计算totalQ和totalRow
			int totalQ = 0;
			int totalRow = 0;
			Billdraftidx billdraftidx = new Billdraftidx();
			billdraftidx.setBilldate(new Date());
			billdraftidx.setBillnumber("222-2222-222-222");
			if (order.getOrder_type() == InventoryOrder.TYPE_SALES_ORDER_W)
				billdraftidx.setBilltype(Billdraftidx.SALES);
			else if (order.getOrder_type() == InventoryOrder.TYPE_SALES_RETURN_ORDER_W)
				billdraftidx.setBilltype(Billdraftidx.RETURN);
			billdraftidx.setA_id(0);
			billdraftidx.setC_id(333);
			billdraftidx.setE_id(userInfor.getJinsuanID());
			billdraftidx.setSout_id(2);
			billdraftidx.setSin_id(2);
			billdraftidx.setAuditman(0);
			billdraftidx.setInputman(userInfor.getJinsuanID());
			billdraftidx.setYsmoney(0);
			billdraftidx.setSsmoney(0);
			billdraftidx.setQuantity(order.getTotalQuantity());
			billdraftidx.setTaxrate(0);
			billdraftidx.setPeriod(0);
			billdraftidx.setBillstates("2");
			billdraftidx.setOrder_id(0);
			billdraftidx.setDepartment_id(0);
//			 billdraftidx.setPosid(0);
			billdraftidx.setRegion_id(0);
//			 billdraftidx.setAuditdate(new Date(0,1,1));
//			 billdraftidx.setSkdate(new Date(0,1,1));
			billdraftidx.setJsye(0);
			billdraftidx.setJsflag("0");
			Date date = new Date();
			DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
			String note = dateFormat.format(date).toString() + " " + order.getClient_name() + order.getOrder_type_ws()
					+ " (" + order.getComment() + "*" + order.getComment2() + ") ";
			note += InventoryOrderDAOImpl.getDaimaiS(order) + " " + InventoryOrderDAOImpl.getMaiduanS(order) + " "
					+ InventoryOrderDAOImpl.getTransferS(order) + " ";
			try {
				note += order.getOrder_Keeper().getName() + "," + order.getOrder_scanner().getName() + ","
						+ order.getOrder_Counter().getName() + ",单号" + orderID;
			} catch (Exception e) {
				loggerLocal.error(e);
			}

			billdraftidx.setInvoice(0);
			billdraftidx.setTranscount(0);
			billdraftidx.setLasttranstime(new Date(0, 1, 1));
			billdraftidx.setGUID(UUID.randomUUID().toString());
			billdraftidx.setInvoiceTotal(0);
			billdraftidx.setInvoiceNO("0");
			billdraftidx.setBusinessType(0);
//			 billdraftidx.setY_id(1);
			billdraftidx.setCurAuditLevel(1);
			billdraftidx.setPRINTCOUNT(0);
			billdraftidx.setPRINTTIME(new Date());
			billdraftidx.setPRINTCOMMENT("");
			billdraftidx.setCanChangeMoney(0);
			billdraftidx.setSizeClassID(-1);
			billdraftidx.setTranFlag(1);
			billdraftidx.setC_ARAPTOTAL(0.00000);
			billdraftidx.setMarketPeriod(0);
			billdraftidx.setsBackGuid("");
			billdraftidx.setMarketCaseId(0);
			billdraftidx.setJsInvoiceTotal(0.00000);
			billdraftidx.setBillDatetime(new Date());
			billdraftidx.setMarketRate(0.00000);
			billdraftidx.setVIPCardID(0);
			billdraftidx.setSummary("");
			billdraftidx.setNote("");

			loggerLocal.info("InventoryService.saveToJinSuan: billdraftidx : " + billdraftidx.getQuantity() + " "
					+ billdraftidx.getNote());

			billdraftidxImpl.save(billdraftidx, false);

			int billid = billdraftidx.getBillid();

			loggerLocal.info("InventoryService.saveToJinSuan: billdraftidx : " + billid);

			double bill_total = 0;
			boolean hasYuRong = false;
			// to get the product barcode, id mapping
			for (InventoryOrderProduct orderProduct : products) {

				int quantity = orderProduct.getQuantity();
				String barcode = orderProduct.getProductBarcode().getBarcode();

				ProductsMS productsMS = productMSMap.get(barcode);
				Product product = productMap.get(barcode).getProduct();
				int productMSID = productsMS.getProductID();
				String comment = product.getUnit();

//new release logic	
				PriceMS priceMS = productsMS.getPrice();
				double retailPrice = priceMS.getRetailprice();
				double recPrice = priceMS.getRecprice();

				double discount = orderProduct.getDiscount();
				double discountPrice = orderProduct.getWholeSalePrice();
				double priceSelected = orderProduct.getSalePriceSelected();
				double salesPrice = priceSelected;

				double salesPriceFactory = product.getSalesPriceFactory();
				if ((salesPriceFactory != 0 && salesPriceFactory != priceSelected) || discount > 1) {
					discount = 1;
					salesPrice = discountPrice;
				}

				double discount_price = Common_util.roundDouble(discountPrice, 2);
				double tax_price = Common_util.roundDouble(discountPrice, 2);
				double new_price = Common_util.roundDouble(discountPrice, 2);

				double totalMoney = Common_util.roundDouble(quantity * discount_price, 2);
				double total_withoutDis = Common_util.roundDouble(quantity * salesPrice, 2);
				double tax_total = Common_util.roundDouble(quantity * tax_price, 2);

				// 验证是否是需要尺码的货品
				int brandId = product.getBrand().getBrand_ID();
				int status = 0;
				if (Brand.SIZE_BRAND.contains(brandId)) {
					status = 1;
					hasYuRong = true;
				}

				bill_total += totalMoney;

				Salemanagebilldrf salemanagebilldrf = new Salemanagebilldrf();
				salemanagebilldrf.setBill_id(billid);
				salemanagebilldrf.setP_id(productMSID);
				salemanagebilldrf.setBatchno("");
				salemanagebilldrf.setQuantity(quantity);
				salemanagebilldrf.setCostprice(recPrice);
				salemanagebilldrf.setSaleprice(salesPrice);
				salemanagebilldrf.setDiscount(discount);
				salemanagebilldrf.setDiscountprice(discount_price);
				salemanagebilldrf.setTotalmoney(totalMoney);
				salemanagebilldrf.setTaxprice(tax_price);
				salemanagebilldrf.setTaxtotal(tax_total);
				salemanagebilldrf.setTaxmoney(0);
				salemanagebilldrf.setRetailprice(retailPrice);
				salemanagebilldrf.setRetailtotal(retailPrice * quantity);
				salemanagebilldrf.setMakedate(new Date(0, 1, 1));
				salemanagebilldrf.setValiddate(new Date(0, 1, 1));
				salemanagebilldrf.setQualitystatus("合格");
				salemanagebilldrf.setPrice_id(0);
				salemanagebilldrf.setSs_id(2);
				salemanagebilldrf.setSd_id(0);
				salemanagebilldrf.setLocation_id(0);
				salemanagebilldrf.setSupplier_id(0);
				salemanagebilldrf.setCommissionflag(0);
				salemanagebilldrf.setComment(comment);
				salemanagebilldrf.setUnitid(productsMS.getUnit_id());
				salemanagebilldrf.setTaxrate(0);
				salemanagebilldrf.setOrder_id(0);
				salemanagebilldrf.setTotal(total_withoutDis);
				salemanagebilldrf.setIotag(0);
				salemanagebilldrf.setInvoiceTotal(0);
				salemanagebilldrf.setThqty(quantity);
				salemanagebilldrf.setNewprice(new_price);
				salemanagebilldrf.setOrgbillid(0);
				salemanagebilldrf.setSizeID(0);
				salemanagebilldrf.setColorID(0);
				salemanagebilldrf.setStatus(status);
				salemanagebilldrf.setInvoice(0);
				salemanagebilldrf.setInvoiceno("");
				salemanagebilldrf.setJSPRICE(0);
				salemanagebilldrf.setGroupid(0);
				salemanagebilldrf.setDraftRowID(0);
				salemanagebilldrf.setAOID(0);
				salemanagebilldrf.setBusinessType(0);
				salemanagebilldrf.setRowTag(0);
				salemanagebilldrf.setRowGuid(UUID.randomUUID().toString());
				salemanagebilldrf.setPriceType("");

				salemanagebilldrfImpl.save(salemanagebilldrf, false);

				loggerLocal.info("InventoryService.saveToJinSuan(): Salemanagebilldrf : order_id:" + orderID
						+ ", Jinsuan id:" + billid + "," + barcode + "," + productMSID + "," + quantity);

				totalQ += quantity;
				totalRow++;
//				 } catch (Exception e) {
//					 loggerLocal.error("InventoryService.saveToJinSuan(): Salemanagebilldrf(ERROR) : order_id:" + orderID +", Jinsuan id:" +billid + "," + productMSID + "," + quantity);
//					 loggerLocal.error(e);
//					 errorMessage = barcode + "-" + quantity + ",";
//				}
			}
			if (hasYuRong)
				note += " (有羽绒服)";

			if (totalQ != order.getTotalQuantity()) {
				errorMessage += "将要导入精算的数量和单据原始数量不一致 : 精算数量" + totalQ + ",原始数量" + order.getTotalQuantity() + "<br/>";
			}
			if (totalRow != products.size()) {
				errorMessage += "将要导入精算的单据总条数和单据原始不一致 : 精算条数" + totalRow + ",单据条数" + products.size() + "<br/> 请检查精算单据";
			}

			if (errorMessage.length() > 0)
				note += "** 导入精算有错误 ,核对初始单据 **";

			billdraftidx.setNote(note);

			billdraftidx.setYsmoney(Common_util.roundDouble(bill_total, 2));
			billdraftidx.setJsye(Common_util.roundDouble(bill_total, 2));

			billdraftidxImpl.update(billdraftidx, false);

			if (errorMessage.length() > 0) {
				loggerLocal.error("导入精算错误 : " + errorMessage);
				response.setFail(errorMessage);
			} else {
				orderCompleteByImportJinsuan(order);

				response.setSuccess("单据成功导入到精算 : " + orderID);
				response.setReturnValue(orderID);
			}
			return response;
		} else {
			response.setFail(errorMessage);
			return response;
		}
	}

	/**
	 * 用户预览单据用
	 * 
	 * @param formBean
	 * @return
	 */
	@Transactional
	public Response previewOrder(int orderId) {
		Response response = new Response();

		InventoryOrder order =  searchByID(orderId);

		if (order == null)
			response.setFail("无法找到单据 : " + orderId);
		else 
		    response.setReturnValue(order);

		return response;
	}

	/**
	 * function to group the products with same barcode
	 * 
	 * @param order
	 * @return
	 */
	private InventoryOrder groupInventoryOrder(InventoryOrder order, String sorting) {
		/**
		 * this is the barcode list with a sequence
		 */
		//条码合计
		Set<String> barcodes = new LinkedHashSet<String>();
		//条码加折扣合计
		Set<String> barcodeDis = new LinkedHashSet<String>();

		/**
		 * 1. to store the non-duplicated product code in a sequence list
		 */
		List<InventoryOrderProduct> orderProducts = order.getProduct_List();
		for (InventoryOrderProduct orderProduct : orderProducts) {
			if (orderProduct != null && orderProduct.getProductBarcode() != null && !orderProduct.getProductBarcode().getBarcode().equals("")) {
				String discount = String.valueOf(orderProduct.getDiscount());
				String barcode = orderProduct.getProductBarcode().getBarcode();
				String mapKey = barcode + discount;
				barcodes.add(barcode);
				barcodeDis.add(mapKey);
			}
		}
		Map<String, ProductBarcode> productMap = productBarcodeDaoImpl.getProductMapByBarcode(barcodes);

		/**
		 * 2. to group the products' quantity
		 */
		HashMap<String, InventoryOrderProduct> orderProductMap = new HashMap<String, InventoryOrderProduct>();
		for (InventoryOrderProduct orderProduct : orderProducts) {
			if (orderProduct != null && orderProduct.getProductBarcode() != null && !orderProduct.getProductBarcode().getBarcode().equals("")) {
				String discount = String.valueOf(orderProduct.getDiscount());
				String barcode = orderProduct.getProductBarcode().getBarcode();

				String mapKey = barcode + discount;

				int boughtBefore = orderProduct.getProductBarcode().getBoughtBefore();
				if (orderProductMap.containsKey(mapKey)) {
					InventoryOrderProduct original_orderProduct = orderProductMap.get(mapKey);
					int addQuantity = orderProduct.getQuantity();
					int orignalQuantity = original_orderProduct.getQuantity();
					original_orderProduct.setQuantity(addQuantity + orignalQuantity);
					if (boughtBefore != 0) {
						original_orderProduct.getProductBarcode().setBoughtBefore(boughtBefore);
					}
				} else {
					orderProductMap.put(mapKey, orderProduct);
				}
			}
		}

		/**
		 * 3. to set the more than two hands
		 */
		Iterator<String> keys = orderProductMap.keySet().iterator();
		while (keys.hasNext()) {
			String key = keys.next();
			InventoryOrderProduct orderProduct = orderProductMap.get(key);

			int q = orderProduct.getQuantity();
			int numPerHand = orderProduct.getProductBarcode().getProduct().getNumPerHand();
			String barcode = orderProduct.getProductBarcode().getBarcode();
			String discount = String.valueOf(orderProduct.getDiscount());

			String mapKey = barcode + discount;

			ProductBarcode product = productMap.get(barcode);
			if (product == null) {
				loggerLocal.error("Could not get the product from Map. Order Id :" + order.getOrder_ID() + ", barcode :"
						+ barcode);
			} else {
				orderProduct.setProductBarcode(product);
			}

			if (q >= numPerHand * 2) {
				orderProduct.setMoreThanTwoHan(true);
			} else {
				orderProduct.setMoreThanTwoHan(false);
			}

			// 2. 设置产品当前的采购成本
			double recCost = this.getProductBarcodeCost(orderProduct.getProductBarcode().getId());
			orderProduct.setRecCost(recCost);

			orderProductMap.put(mapKey, orderProduct);
		}

		/**
		 * 4. rebuild the product list
		 */
		if (sorting.equalsIgnoreCase("true")) {
			Collection<InventoryOrderProduct> OrderProducts_c = orderProductMap.values();
			List<InventoryOrderProduct> newOrderProducts = new ArrayList<InventoryOrderProduct>();
			newOrderProducts.addAll(OrderProducts_c);
			Collections.sort(newOrderProducts, new SortByBrandProductCode());
			order.setProduct_List(newOrderProducts);
			return order;
		} else {
			List<InventoryOrderProduct> OrderProducts_org = new ArrayList<InventoryOrderProduct>();
			for (String barcodeD : barcodeDis) {
				OrderProducts_org.add(orderProductMap.get(barcodeD));
			}
			order.setProduct_List(OrderProducts_org);
			return order;
		}

	}

	/**
	 * 仓库提交单据给会计
	 * 
	 * @param order
	 * @return
	 * @throws Exception
	 */
	@Transactional
	public Response inventoryComplsave(InventoryOrderActionFormBean formBean, UserInfor auditor) {
		Response response = new Response();

		/**
		 * 1. save the order
		 */
		InventoryOrder order = groupInventoryOrder(formBean.getOrder(), formBean.getSorting());
		// 添加库存信息
		// order.setStore(formBean.getOrder().getStore());
		// 将精算客户信息添加到总部headCust表中

		order.setOrder_Status(InventoryOrder.STATUS_ACCOUNT_PROCESS);

		order.setOrder_ComplTime(new Date());

		// order.setOrder_Auditor(auditor);

		try {
			response = save(order);

		} catch (Exception e) {
			loggerLocal.error(e);
			response.setFail(e.getMessage());
		} finally {
			response.setAction(order.getOrder_type());

		}

		return response;
	}
	

	/**
	 * 精算客户信息添加到head_cust
	 * 
	 * @param clientId
	 */
	public void copyJSuserInfo(int clientId,UserInfor auditor) {
		ClientsMS cMs = clientImpl.get(clientId, true);
		RegionMS rMs = regionMSDAOImpl.get(cMs.getRegion_id(), true);
		HeadQCust headQCust = headQCustDaoImpl.get(clientId, true);

		if (headQCust == null) {
			headQCust = new HeadQCust();
			headQCust.setId(cMs.getClient_id());
			headQCust.setCreationDate(new Date());
			headQCust.setInitialAcctBalance(0.0);
			headQCust.setCurrentAcctBalance(0.0);
			headQCust.setStatus(HeadQCust.STATUS_GOOD);
			headQCust.setComment(Common_util.getToday() +": 新增客户");	
			headQCust.setCreationDate(Common_util.getToday());
		}
			
		headQCust.setName(cMs.getName());
		headQCust.setPinyin(cMs.getPinyin());
		headQCust.setAddress(cMs.getAddress());
		headQCust.setPhone(cMs.getPhoneNumber());
		if (rMs != null) {
			headQCust.setArea(rMs.getName());
		} else {
			headQCust.setArea("");
		}			
		headQCust.setLastUpdateBy(auditor.getUser_name());
		headQCust.setLastUpdateTime(Common_util.getToday());
		headQCustDaoImpl.saveOrUpdate(headQCust, true);

	} 

	/**
	 * inventroy submit the order to account
	 * 
	 * @param order
	 * @return
	 * @throws Exception
	 */
	@Transactional
	public Response saveToDraft(InventoryOrder order, String sorting,UserInfor auditor) throws Exception {
		Response response = new Response();
		int orderId = order.getOrder_ID();
		if (orderId != 0) {
			InventoryOrder orderInDB = inventoryOrderDAOImpl.get(orderId, true);

			if (orderInDB.getOrder_Status() != InventoryOrder.STATUS_DRAFT) {
				response.setFail("当前单据状态(" + orderInDB.getOrder_Status_s() + "),不能再次保存草稿");
				return response;
			}
		}

		order.setOrder_Status(InventoryOrder.STATUS_DRAFT);

		order = groupInventoryOrder(order, sorting);

		response.setAction(order.getOrder_type());

		return save(order);
	}

	/**
	 * search the order by the search criteria from the web page
	 * 
	 * @param formBean
	 * @return
	 */
	public List<InventoryOrder> search(InventoryOrderActionFormBean formBean, String sort, String ordering) {
		DetachedCriteria criteria = DetachedCriteria.forClass(InventoryOrder.class, "order");

		InventoryOrder searchBean = formBean.getOrder();

		//单据号不为空且单据号为纯数字
		if (searchBean.getOrderId() != null && StrCheckUtils.isNumber(Integer.toString(searchBean.getOrderId()))) {
			criteria.add(Restrictions.eq("order.order_ID", searchBean.getOrderId()));

			criteria.add(Restrictions.ne("order.order_Status", InventoryOrder.STATUS_DELETED));
		} else {
			Date startTime = formBean.getSearch_Start_Time();
			Date endTime = formBean.getSearch_End_Time();

//			if (searchBean.getOrder_Status() != Common_util.ALL_RECORD)
//				criteria.add(Restrictions.eq("order.order_Status", searchBean.getOrder_Status()));
//			else
//				criteria.add(Restrictions.ne("order.order_Status", InventoryOrder.STATUS_DELETED));
			
			if(StringUtils.isNotBlank(searchBean.getOrderStatus())) {
				String status = searchBean.getOrderStatus();
				List<String> sts = Arrays.asList(status.split(","));
				List<Integer> st =new ArrayList<Integer>();
				for (String s : sts) {
					st.add(Integer.valueOf(s));
				}
				criteria.add(Restrictions.in("order.order_Status",st));
			}else {
				criteria.add(Restrictions.ne("order.order_Status", InventoryOrder.STATUS_DELETED));
			}

			if (searchBean.getClient_id() != 0 && !searchBean.getClient_name().equals("")) {
				int clientid = searchBean.getClient_id();

				criteria.add(Restrictions.eq("order.client_id", clientid));
			} else if (StringUtils.isNotBlank(formBean.getTagGroups())){
				List<Integer> cIds = inventoryOrderDAOImpl.selectCIdsByOrderTime(startTime,endTime);
				List<Integer> clientIds = headQCustDaoImpl.getTagGroupsCusts(formBean.getTagGroups());
				//如果是根据客户标签查找单据，则取时间范围内客户和标签客户交集，缩小客户范围			
				cIds.retainAll(clientIds);
				criteria.add(Restrictions.in("order.client_id", cIds));
			}

			String comment = formBean.getOrder().getComment().trim();
			if (!StringUtils.isEmpty(comment)) {
				criteria.add(Restrictions.or(Restrictions.like("order.comment", comment, MatchMode.ANYWHERE),
						Restrictions.like("order.comment2", comment, MatchMode.ANYWHERE)));
			}

			if (searchBean.getOrder_Auditor() != null
					&& searchBean.getOrder_Auditor().getUser_id() != Common_util.ALL_RECORD)
				criteria.add(
						Restrictions.eq("order.order_Auditor.user_id", searchBean.getOrder_Auditor().getUser_id()));

			if (startTime != null && endTime != null) {
				Date end_date = Common_util.formEndDate(endTime);
				criteria.add(Restrictions.between("order.order_StartTime", startTime, end_date));
			}

			if (searchBean.getOrder_type() != Common_util.ALL_RECORD)
				criteria.add(Restrictions.eq("order.order_type", searchBean.getOrder_type()));

			if (!StringUtils.isEmpty(formBean.getPbIds())) {
				String[] productIds = formBean.getPbIds().split(",");
				if (productIds.length > 0) {
					Set<Integer> productIdSet = new HashSet<Integer>();
					for (String id : productIds) {
						productIdSet.add(Integer.parseInt(id));
					}
					DetachedCriteria inventoryProduct = criteria.createCriteria("product_Set");
					inventoryProduct.add(Restrictions.in("productBarcode.id", productIdSet));

				}
			}
			if (searchBean.getStore().getId() != Common_util.ALL_RECORD) {
				criteria.add(Restrictions.eq("order.store.id", searchBean.getStore().getId()));
			}

			String sortSQL = "";
			if (sort.equals("startTime")) {
				sortSQL = "order.order_StartTime";
			} else if (sort.equals("completeTime")) {
				sortSQL = "order.order_EndTime";
			} else if (sort.equals("auditorName")) {
				sortSQL = "order.order_Auditor.user_id";
			} else if (sort.equals("maiduan")) {
				sortSQL = "order.isMaiduan";
			} else if (sort.equals("daimai")) {
				sortSQL = "order.isDaimai";
			} else if (sort.equals("transfer")) {
				sortSQL = "order.isTransfer";
			} else if (sort.equals("orderType")) {
				sortSQL = "order.order_type";
			} else if (sort.equals("importTimes")) {
				sortSQL = "order.importTimes";
			} else if (sort.equals("process")) {
				sortSQL = "order.order_Status";
			} else if (sort.equals("clientName")) {
				sortSQL = "order.client_name";
			} else if (sort.equals("PDAUserName")) {
				sortSQL = "order.pdaScanner.user_id";
			} else if (sort.equals("storeName")) {
				sortSQL = "order.store.id";
			} else if (sort.equals("keeperName")) {
				sortSQL = "order.order_Keeper.user_id";
			}

			System.out.println(sortSQL);

			if (ordering.equalsIgnoreCase("asc"))
				criteria.addOrder(Order.asc(sortSQL));
			else
				criteria.addOrder(Order.desc(sortSQL));
		}
		return inventoryOrderDAOImpl.search(criteria);
	}



	/**
	 * function to get the order by id
	 * 
	 * @param order_ID
	 * @return
	 */
	@Transactional
	public InventoryOrder searchByID(int order_ID) {
		InventoryOrder order_r = inventoryOrderDAOImpl.retrieveOrder(order_ID);

		order_r.putSetToList();

		return order_r;
	}

	/**
	 * This is a common function that will be used by other save functions it will
	 * build the index and put the list to set when save
	 * 
	 * @param order
	 * @return
	 * @throws Exception
	 */
	private Response save(InventoryOrder order) {
		Response response = new Response();

		response = inventoryOrderValidate(order);
		if (!response.isSuccess())
			return response;

		/**
		 * if order_org == null, it is a newly inserted draft order. or it is drafted
		 * before, we need check whether we shall delete records
		 */
		int orderId = order.getOrder_ID();

		if (orderId != 0) {
			// 1. to check the non exist products
			InventoryOrder order_org = inventoryOrderDAOImpl.retrieveOrder(orderId);
			order_org.putSetToList();
			List<Integer> Products_org = retrieveProductID(order_org.getProduct_List());
			List<Integer> products_form = retrieveProductID(order.getProduct_List());
			Set<Integer> delete_id = new HashSet<Integer>();
			for (int i : Products_org) {
				if (!products_form.contains(i))
					delete_id.add(i);
			}

			// 2. to check the quantity is zero
			List<InventoryOrderProduct> products = order.getProduct_List();
			for (InventoryOrderProduct product : products) {
				if (product != null) {
					int quantity = product.getQuantity();
					if (quantity == 0)
						delete_id.add(product.getID());
				}
			}

			if (delete_id.size() > 0)
				inventoryOrderProductDAOImpl.deleteInventoryProducts(delete_id);

			inventoryOrderDAOImpl.evict(order_org);
		}

		// 单据可能没有Pda scanner，需要使用null处理
		if (order.getPdaScanner() != null && order.getPdaScanner().getUser_id() == 0) {
			order.setPdaScanner(null);
		}

		// 做一个保存前的验证
		// 验证数据不会丢失
		order.buildIndex();
		order.putListToSet();
		inventoryOrderDAOImpl.saveOrUpdate(order, true);

		return response;
	}

	/**
	 * 验证单据的整体性， 
	 * 1. 验证单据是否填写完成 
	 * 2. 验证细条数据的合计总数能和总数对上
	 * 3. 验证千禧/禧乐仓客户 与 货品能否匹配
	 * 
	 * @param order
	 * @return
	 */
	private Response inventoryOrderValidate(InventoryOrder order) {
		Response response = new Response();
		String errorMsg = "";

		if (order.getClient_id() == 0)
			errorMsg += "客户名字必填<br/>";

		if (order.getOrder_Keeper() == null)
			errorMsg += "订单输入人员必填<br/>";

		if (order.getOrder_Counter() == null)
			errorMsg += "订单点数人员必填<br/>";

		if (order.getOrder_scanner() == null)
			errorMsg += "订单扫描人员必填<br/>";

		if (order.getStore() == null || order.getStore().getId() == 0)
			errorMsg += "库房必选<br/>";
		HeadQCust hCust = new HeadQCust();
		if (order.getClient_id() !=0) {
			 hCust = headQCustDaoImpl.get(order.getClient_id(), true);
			if (hCust == null) {
				errorMsg += "系统上不存在该客户无法创建单据<br/>";
			} else if (hCust.getStatus() == HeadQCust.STATUS_DELETED) {
				errorMsg += "该客户已冻结,冻结客户无法创建单据<br/>";
			}
		}

		//验证基本信息
		if (errorMsg.length() > 0) {
			response.setFail(errorMsg);
			return response;
		}
		
		//验证单据不能同时为 买断 和 代卖
		if (order.getIsDaimai()>0 && order.getIsMaiduan() >0) {
			response.setFail("单据不能同时为 代卖 和 买断,否则会影响报表数据");
			return response;
		}
		
		//验证客户，库房，产品是否为同一归属
		response = isCheckQxOrXlc(order);
		if (!response.isSuccess() ){
			return response;
		}


		int totalQOnPage = order.getTotalQuantity();
		int totalQCal = 0;
		int qRow = 0;
		List<InventoryOrderProduct> products = order.getProduct_List();
		for (InventoryOrderProduct product : products) {
			if (product != null && product.getProductBarcode() != null
					&& product.getProductBarcode().getBarcode() != null
					&& !product.getProductBarcode().getBarcode().trim().equals("")) {
				qRow = product.getQuantity();				
				loggerLocal.info("---条码---" + product.getProductBarcode().getBarcode() + "---折扣---" + product.getDiscount() + "---数量 --- " + product.getQuantity());
				totalQCal += qRow;
			}
		}
		

		if (totalQCal != totalQOnPage) {
			response.setFail("单据的实际总数(" + totalQCal + ")与页面总数(" + totalQOnPage + ")不一致<br/>请点击重新计算后再核实单据明细");
		}
		return response;
	}
	
	
	/**
	 * 验证客户，库房，产品是否为同一归属
	 * @param order
	 * @return
	 */
	private Response isCheckQxOrXlc(InventoryOrder order) {
		Response response = new Response();
		int belongTo = 0;
		String errorMsg = "";
		
		String custTitle = "";

		// 1.判断客户是千禧客户 || 禧乐仓客户
		HeadqEntityTag qxEntityTag = entityTagDaoImpl.selectEntityTag(order.getClient_id(),
				SystemParm.getQxCustTagId());
		if (qxEntityTag != null) {
			belongTo = Common_util.QX_RANGE;
			custTitle = "千禧";
		}
		HeadqEntityTag xEntityTag = entityTagDaoImpl.selectEntityTag(order.getClient_id(),
				SystemParm.getXlcCustTagId());
		if (xEntityTag != null) {
			belongTo = Common_util.XLC_RANGE;
			custTitle = "禧乐仓";
		}
		if (qxEntityTag == null && xEntityTag == null) {
			response.setFail("当前客户未选择归属,非总部千禧或禧乐仓客户");
		} else {
			//库房
			HeadQInventoryStore store = headQInventoryStoreDAOImpl.get(order.getStore().getId(), true);
			if (store.getBelongTo() != belongTo) {
				response.setReturnCode(Response.FAIL);
				errorMsg += custTitle + "客户无法选择:" + HeadQInventoryStore.belongToMap.get(store.getBelongTo()) + "库房<br>";
			}
			
			if (order.getProduct_List().size() != 0) {
					for (InventoryOrderProduct product : order.getProduct_List()) {
						Brand brand = product.getProductBarcode().getProduct().getBrand();
						if (brand != null && brand.getBelong_To() != belongTo) {
							errorMsg += custTitle+ "客户无法选择" + Brand.belongToMap.get(brand.getBelong_To()) + "货品，条码："
									+ product.getProductBarcode().getBarcode()+ "<br>";
							response.setReturnCode(Response.FAIL);
						}
					}
			}
			
				
			if (!response.isSuccess())
				  response.setFail(errorMsg);
		}
		return response;
	}
	

	private List<Integer> retrieveProductID(List<InventoryOrderProduct> products) {
		List<Integer> ids = new ArrayList<Integer>();
		for (InventoryOrderProduct product : products) {
			if (product != null)
				ids.add(product.getID());
		}
		return ids;
	}

	/**
	 * to delete a order by mark it as deleted status but if the order has been
	 * finished by acct, it can only be 红冲
	 * 
	 * @param order_ID
	 */
	public Response delete(int order_ID) {
		InventoryOrder order = inventoryOrderDAOImpl.get(order_ID, true);
		Response response = new Response();

		if (order != null && order.getOrder_Status() != InventoryOrder.STATUS_ACCOUNT_COMPLETE) {
			String hql_order = "UPDATE InventoryOrder i set i.order_Status = ? where order_ID = ?";
			Object[] values = { InventoryOrder.STATUS_DELETED, order_ID };

			inventoryOrderDAOImpl.executeHQLUpdateDelete(hql_order, values, true);
			response.setReturnCode(Response.SUCCESS);
		} else {
			response.setReturnCode(Response.FAIL);
		}

		return response;
	}

	/**
	 * 通过授权删除单据 but if the order has been finished by acct, it can only be 红冲
	 * 
	 * @param order_ID
	 */
	@Transactional
	public Response deleteByAuthorization(int order_ID, String userName, String password) {
		// 1. 验证用户名和密码
		Response response = userInforService.validateUser(userName, password);

		if (response.getReturnCode() == Response.SUCCESS) {
			UserInfor user = (UserInfor) response.getReturnValue();
			userInforService.setFunctions(user);
			if (!user.getFunctions().contains(RoleFunctionality.CONFIRM_ORDER_DELETE)) {
				response.setQuickValue(Response.FAIL, userName + " 还没有删除单据权限");
			} else {
				InventoryOrder order = inventoryOrderDAOImpl.get(order_ID, true);

				if (order != null && order.getOrder_Status() != InventoryOrder.STATUS_ACCOUNT_COMPLETE) {
					String hql_order = "UPDATE InventoryOrder i set i.order_Status = ? where order_ID = ?";
					Object[] values = { InventoryOrder.STATUS_DELETED, order_ID };

					inventoryOrderDAOImpl.executeHQLUpdateDelete(hql_order, values, true);
					response.setSuccess("单据(" + order_ID + ")已经删除");
				} else {
					response.setQuickValue(Response.FAIL, order_ID + " 单据已经会计过账,不能删除");
				}
			}
		}
		return response;
	}

	/**
	 * the service to cancel the order 红冲单据
	 * 
	 * @param orderId
	 * @return
	 */
	@Transactional
	public Response cancel(UserInfor userInfor, int orderId) {
		InventoryOrder order = inventoryOrderDAOImpl.get(orderId, true);
		Response response = new Response();

		if (order == null) {
			response.setFail("无法找到单据 : " + orderId);
			return response;
		}

		if (order.getOrder_Status() == InventoryOrder.STATUS_ACCOUNT_COMPLETE) {
			ChainStore chainStore = chainStoreDaoImpl.getByClientId(order.getClient_id());

			// 如果是连锁店客户，需要检查连锁店是否已经确认收货
			if (chainStore != null) {
				// 1. 检查客户是否已经验收了
				String url = SystemParm.getParm("CHAIN_INVENTORY_SERVICE");
				// 要传的参数
				String s = null;
				String result = null;
				try {
                    s="formBean.order.order_ID="+orderId+"&formBean.serviceId=1";
					result = HttpUtil.callRemoteService(url, s);

					JSONObject jsonObject = JSONObject.fromObject(result);

					Response loginResponse = (Response) JSONObject.toBean(jsonObject, Response.class);
					if (loginResponse.getReturnCode() == Response.SUCCESS) {
						Object returnValue = loginResponse.getReturnValue();
						jsonObject = JSONObject.fromObject(returnValue);
						InventoryOrderVO inventoryOrderVO = (InventoryOrderVO) JSONObject.toBean(jsonObject,
								InventoryOrderVO.class);

						if (inventoryOrderVO.getStatus() == InventoryOrder.STATUS_CHAIN_CONFIRM
								|| inventoryOrderVO.getStatus() == InventoryOrder.STATUS_SYSTEM_CONFIRM) {
							response.setQuickValue(Response.WARNING, "客户已经确认此单据收货，无法红冲。请与管理员联系");
							return response;
						}
					} else {
						response.setQuickValue(Response.FAIL, loginResponse.getMessage());
						return response;
					}
				} catch (Exception e) {
					e.printStackTrace();
					response.setFail("检查远程服务器数据失败，请联系管理员 : " + e.getMessage());
					return response;
				}
			}

			// 1. to update the order status
			String hql_order = "UPDATE InventoryOrder i set i.order_Status = ?, i.order_Auditor.user_id=? where order_ID = ?";
			Object[] values = { InventoryOrder.STATUS_CANCELLED, userInfor.getUser_id(), orderId };
			inventoryOrderDAOImpl.executeHQLUpdateDelete(hql_order, values, true);

			// 2. to update the chain in-out stock
//			updateChainInOutStock(order, true);

			// 3. to update the acct flow
			updateChainAcctFlow(order, order.getOrder_EndTime(), true);

			// 4. to update the headq stock
			updateHeadqInventory(order, true);

			response.setSuccess("成功红冲单据 : " + orderId);
		} else {
			response.setFail("会计未过账的单据不能红冲,只能删除");
		}

		return response;
	}

	/**
	 * function to copy the order
	 * 
	 * @param loginUserInfor
	 * @param order
	 * @return
	 * @throws Exception
	 */
	@Transactional
	public Response copyOrder(UserInfor loginUserInfor, InventoryOrder order) {
		Response response = new Response();
		int orderId = order.getOrder_ID();

		if (orderId > 0) {
			InventoryOrder orderInDB = inventoryOrderDAOImpl.retrieveOrder(orderId);
			order = inventoryOrderDAOImpl.copy(orderInDB);
			String comment = order.getComment2();

			order.setComment2(comment + "\n 复制于单据" + orderId);
			order.setOrder_Auditor(loginUserInfor);
			order.setOrder_Status(InventoryOrder.STATUS_ACCOUNT_PROCESS);
			order.setImportTimes(0);

			inventoryOrderDAOImpl.save(order, true);

			response.setReturnCode(Response.SUCCESS);
			response.setReturnValue(order.getOrder_ID());
		} else
			response.setReturnCode(Response.FAIL);

		return response;
	}

	/**
	 * 会计保存单据
	 * 
	 * @param order
	 * @return
	 * @throws Exception
	 */
	@Transactional
	public Response acctEditAndSave(InventoryOrderActionFormBean formBean, UserInfor order_Auditor) {
		Response response = new Response();

		int orderId = formBean.getOrder().getOrder_ID();
		response.setReturnValue(orderId);

		InventoryOrder orderInDB = inventoryOrderDAOImpl.retrieveOrder(orderId);

		if (orderInDB.getOrder_Status() != InventoryOrder.STATUS_ACCOUNT_PROCESS
				&& orderInDB.getOrder_Status() != InventoryOrder.STATUS_WAITING_AUDIT) {
			response.setFail("当前单据状态(" + orderInDB.getOrder_Status_s() + "),不能再次修改");
			return response;
		}

		InventoryOrder order = groupInventoryOrder(formBean.getOrder(), formBean.getSorting());
		order.setOrder_Auditor(order_Auditor);
		order.setOrder_ComplTime(new Date());

		response = save(order);
		response.setReturnValue(orderId);

		return response;
	}

	/**
	 * 完成精算导入之后，只要修改状态和sales history
	 * 
	 * 
	 * @param Status
	 * @param order_id
	 */
	private void orderCompleteByImportJinsuan(InventoryOrder order) {
		// 1. 检查是否需要自动审核
		int clientId = order.getClient_id();
//		ChainStore chainStore = chainStoreDaoImpl.getByClientId(clientId);
		int orderStatus = InventoryOrder.STATUS_WAITING_AUDIT;
//连锁店和非连锁店客户都需要会计审核
//		if (chainStore == null)
//			orderStatus = InventoryOrder.STATUS_ACCOUNT_COMPLETE;

		// 2. update the order information
		int order_id = order.getOrder_ID();
		int importTimes = order.getImportTimes() + 1;
		Date now = new Date();
		
		loggerLocal.info("更新order" + order_id + "导入精算次数 : " + order.getImportTimes());
		String hql = "update InventoryOrder set order_Status =?, order_EndTime=?, importTimes=? where order_ID=?";
		Object[] values = { orderStatus, now, importTimes, order_id };
		inventoryOrderDAOImpl.executeHQLUpdateDelete(hql, values, false);

	}

	/**
	 * to change the order status and the times import to jinsuan
	 * 
	 * @param Status
	 * @param order_id
	 */
	@Transactional
	public Response orderCompleteAudit(int orderId, UserInfor auditor) {
		loggerLocal.info("------审核单据---- : " + orderId);
		Response response = new Response();

		InventoryOrder order = inventoryOrderDAOImpl.get(orderId, true);

		// 验证当前用户不是审核人员
		if (auditor.getUser_id() != order.getOrder_Auditor().getUser_id()) {
			response.setFail("你不是当前单据的审核员，无法过账。 请联系单据审核员 : " + order.getOrder_Auditor().getName());
			return response;
//无论什么客户都需要			
//		}else if (chainStore == null && orderStatus == InventoryOrder.STATUS_ACCOUNT_PROCESS) {
//			response.setReturnCode(Response.FAIL);
//			response.setMessage("客户不属于连锁店客户,不能在导入精算前直接审核");
//			InventoryOrder originalOrder = searchByID(orderId);
//			response.setReturnValue(originalOrder);
		}

		// 只有会计录入中的单据才能审核入账
		if (order.getOrder_Status() == InventoryOrder.STATUS_ACCOUNT_PROCESS
				|| order.getOrder_Status() == InventoryOrder.STATUS_WAITING_AUDIT) {
			Date now = new Date();
			String hql = "update InventoryOrder set order_Status =?, order_EndTime=? where order_ID=?";

			Object[] values = { InventoryOrder.STATUS_ACCOUNT_COMPLETE, now, orderId };

			inventoryOrderDAOImpl.executeHQLUpdateDelete(hql, values, false);

			// 2. update the sales history
			updateSalesHistory(order);

			// 3. update the Chain's InOut stock
//			updateChainInOutStock(order, false);

			// 3.更新总部库存
			updateHeadqInventory(order, false);
			
			if (order.getOrder_type() != InventoryOrder.TYPE_SALES_FREE_ORDER_W) {
			// 4. update the acct flow
			updateChainAcctFlow(order, now, false);
			}

			response.setSuccess("单据审核成功完成");
		} else {
			response.setFail("当前单据状态(" + order.getOrder_Status_s() + ")不是 会计录入中/待审核 ,不能直接完成审核");
		}

		return response;
	}

	/**
	 * 方法用于inventory 更新总部的库存
	 * 
	 * @param order
	 * @param isCancel
	 */
	private void updateHeadqInventory(InventoryOrder order, boolean isCancel) {
		int orderId = order.getOrder_ID();
		String inventoryStockId = "";

		// 更新库存数据
		HeadQInventoryStore store = order.getStore();
		int storeId = HeadQInventoryStore.INVENTORY_STORE_DEFAULT_ID;

		if (store != null)
			storeId = store.getId();
		else
			return;

		int offset = 1;
		if (isCancel) {
			offset = -1;
			inventoryStockId = "C";
		}

		if(order.getOrder_type() == InventoryOrder.TYPE_SALES_ORDER_W)  {//批发销售				
				offset *= -1;
				inventoryStockId += HeadQInventoryStock.WHOLE_SALES + orderId;				
		}else if (order.getOrder_type() == InventoryOrder.TYPE_SALES_RETURN_ORDER_W) {//批发退货
			inventoryStockId += HeadQInventoryStock.WHOLE_RETURN + orderId;
		} else if(order.getOrder_type() == InventoryOrder.TYPE_SALES_FREE_ORDER_W) {//批发赠送
			offset *= -1;
			inventoryStockId += HeadQInventoryStock.WHOLE_FREE + orderId;
		}

		Iterator<InventoryOrderProduct> orderProducts = order.getProduct_Set().iterator();
		while (orderProducts.hasNext()) {
			InventoryOrderProduct orderProduct = orderProducts.next();
			int pbId = orderProduct.getProductBarcode().getId();

			int quantity = orderProduct.getQuantity() * offset;
			double cost = orderProduct.getRecCost();
			double discount = orderProduct.getDiscount();

			if (cost == 0) {
				cost = this.getProductBarcodeCost(pbId);
			}

			double costTotal = cost * quantity;
			double wholeSalePrice = orderProduct.getWholeSalePrice();
			double wholeSalesTotal = wholeSalePrice * quantity;

			ProductBarcode pb = productBarcodeDaoImpl.get(pbId, true);

			HeadQInventoryStock stock = new HeadQInventoryStock();
			if (order.getOrder_type() == InventoryOrder.TYPE_SALES_FREE_ORDER_W) {
				stock = new HeadQInventoryStock(storeId, pb, inventoryStockId, quantity, cost,
						wholeSalePrice, 0, 0,discount,new Date());
			}else {
				stock = new HeadQInventoryStock(storeId, pb, inventoryStockId, quantity, cost,
						wholeSalePrice, costTotal, wholeSalesTotal,discount,new Date());
			}

			headQInventoryStockDAOImpl.save(stock, true);
		}
	}

	/**
	 * 更新单据的成本 和 销售历史数据
	 * 
	 * @param order
	 */

	private void updateSalesHistory(InventoryOrder order) {
		int isDaimai = order.getIsDaimai();
		int isMaiduan = order.getIsMaiduan();
		int isTransfer = order.getIsTransfer();
		// save the product sales price information to history table, if it is a sales
		// order
		if (order.getOrder_type() == InventoryOrder.TYPE_SALES_ORDER_W) {
			Set<HeadQSalesHistory> historySet = new HashSet<HeadQSalesHistory>();
			Iterator<InventoryOrderProduct> orderProducts = order.getProduct_Set().iterator();
			while (orderProducts.hasNext()) {
				InventoryOrderProduct orderProduct = orderProducts.next();

				int pbId = orderProduct.getProductBarcode().getId();
				ProductBarcode pBarcode = productBarcodeDaoImpl.get(pbId, true);
				HeadqPurchaseHistory history = headqPurchaseHistoryDaoImpl.get(pbId, true);
				double cost = pBarcode.getProduct().getRecCost();
				if (history != null)
					cost = history.getRecCost();

				orderProduct.setRecCost(cost);
				inventoryOrderProductDAOImpl.update(orderProduct, true);				

				HeadQSalesHistory salesHistory;
				salesHistory = new HeadQSalesHistory(orderProduct.getProductBarcode().getId(), order.getClient_id(),
						cost, orderProduct.getWholeSalePrice(), orderProduct.getSalesPrice(),
						orderProduct.getQuantity(), orderProduct.getSalePriceSelected(), orderProduct.getDiscount(),
						isDaimai, isMaiduan, isTransfer);
				historySet.add(salesHistory);
			}

			Iterator<HeadQSalesHistory> historyIt = historySet.iterator();
			while (historyIt.hasNext()) {
				HeadQSalesHistory history = historyIt.next();
				headQSalesHisDAOImpl.saveOrUpdate(history, false);
			}
		}
	}

	/**
	 * to update the chain's acct flow 更新客户和连锁店账目流水
	 * 
	 * @param order
	 * @param b
	 */
	private void updateChainAcctFlow(InventoryOrder order, Date date, boolean isCancel) {

		int clientId = order.getClient_id();

		HeadQCust cust = headQCustDaoImpl.get(clientId, true);

		ChainStore chainStore = chainStoreDaoImpl.getByClientId(clientId);
		int chainId = 0;
		if (chainStore != null)
			chainId = chainStore.getChain_id();

		int orderId = order.getOrder_ID();
		int orderType = order.getOrder_type();
		double totalAmt = order.getTotalWholePrice();
		double totalDis = order.getTotalDiscount();
		double netAmt = totalAmt - totalDis;

		// 1. update the offset
		int offset = 1;
		if (orderType == InventoryOrder.TYPE_SALES_RETURN_ORDER_W)
			offset *= -1;
		else if (orderType == InventoryOrder.TYPE_SALES_FREE_ORDER_W)
			offset = 0;

		if (isCancel)
			offset *= -1;

		netAmt *= offset;

		// 2.update the order's preAcctAmt and postAcctAmt
		double preAcctAmt = calculatePreAcctBalance(clientId);
		double postAcctAmt = Common_util.getDecimalDouble(preAcctAmt + netAmt);
		if (!isCancel) {
			String hql = "update InventoryOrder set preAcctAmt =?, postAcctAmt=? where order_ID=?";
			Object[] values = { preAcctAmt, postAcctAmt, orderId };

			inventoryOrderDAOImpl.executeHQLUpdateDelete(hql, values, false);
		}
		loggerLocal.info("------审核单据---- : " + orderId + " , " + preAcctAmt + " , " + postAcctAmt);

		ChainAcctFlow chainAcctFlow = new ChainAcctFlow(clientId, netAmt, "S," + orderId + "," + isCancel, date,
				chainId);
		chainAcctFlowDaoImpl.save(chainAcctFlow, true);
		
		//重新获取客户的最新欠款(防止会计修改系统时间后获取错误信息)
		double acctAmt = calculatePreAcctBalance(clientId);
		cust.setCurrentAcctBalance(acctAmt);
		headQCustDaoImpl.update(cust, true);

	}

	/**
	 * to generate the excel order
	 * 
	 * @param order
	 * @param templatePosition
	 * @return
	 */
	@Transactional
	public Map<String, Object> generateExcelReport(InventoryOrder order, String templatePosition) {
		Map<String, Object> returnMap = new HashMap<String, Object>();

		ByteArrayInputStream byteArrayInputStream;
		try {
			HSSFWorkbook wb = null;

			// to get the order information from database
			order = inventoryOrderDAOImpl.retrieveOrder(order.getOrder_ID());
			InventoryOrderTemplate orderTemplate = new InventoryOrderTemplate(order, templatePosition);

			wb = orderTemplate.process();

			ByteArrayOutputStream os = new ByteArrayOutputStream();
			try {
				wb.write(os);
			} catch (IOException e) {
				loggerLocal.error(e);
			}
			byte[] content = os.toByteArray();
			byteArrayInputStream = new ByteArrayInputStream(content);
			returnMap.put("stream", byteArrayInputStream);

			return returnMap;
		} catch (Exception ex) {
			loggerLocal.error(ex);
		}
		return null;
	}

	/**
	 * to generate the Jinsuan order to print the label
	 * 
	 * @param order
	 * @param string
	 * @return
	 */
	@Transactional
	public Map<String, Object> generateJinsuanExcelReport(InventoryOrder order, String templatePosition) {
		Map<String, Object> returnMap = new HashMap<String, Object>();

		ByteArrayInputStream byteArrayInputStream;
		try {
			HSSFWorkbook wb = null;

			// to get the order information from database
			order = inventoryOrderDAOImpl.retrieveOrder(order.getOrder_ID());
			JinSuanOrderTemplate orderTemplate = new JinSuanOrderTemplate(order, templatePosition);

			wb = orderTemplate.process();

			ByteArrayOutputStream os = new ByteArrayOutputStream();
			try {
				wb.write(os);
			} catch (IOException e) {
				loggerLocal.error(e);
			}
			byte[] content = os.toByteArray();
			byteArrayInputStream = new ByteArrayInputStream(content);
			returnMap.put("stream", byteArrayInputStream);

			// 2. check the file name
			int clientId = order.getClient_id();
			ChainStore store = chainStoreDaoImpl.getByClientId(clientId);
			if (store != null) {
				ChainPriceIncrement priceIncrement = store.getPriceIncrement();
				if (priceIncrement != null) {
					String fileExt = "";
					priceIncrement = chainPriceIncrementDaoImpl.get(priceIncrement.getId(), true);
					if (priceIncrement.getIncrementType() == ChainPriceIncrement.TYPE_MULTIPLE) {
						fileExt += "_m_" + "1." + String.valueOf((int) priceIncrement.getIncrement());
					} else if (priceIncrement.getIncrementType() == ChainPriceIncrement.TYPE_ADD) {
						fileExt += "_a_" + String.valueOf((int) priceIncrement.getIncrement());
					}
					returnMap.put("fileExt", fileExt);
				}
			}

			return returnMap;
		} catch (Exception ex) {
			loggerLocal.error(ex);
		}
		return null;
	}
	
	
	/**
	 * to generate the Jinsuan order to print the label
	 * 
	 * @param order
	 * @param string
	 * @return
	 */
	@Transactional
	public Map<String, Object> generateJinsuanExcelReports(String orderIds, String templatePosition) {
		Map<String, Object> returnMap = new HashMap<String, Object>();
		List<InventoryOrder> list = new ArrayList<InventoryOrder>();

		ByteArrayInputStream byteArrayInputStream;
		try {
			HSSFWorkbook wb = null;

			if (StringUtils.isNotBlank(orderIds)) {
				
				String idArray[] = orderIds.split(",");
				for (String orderId : idArray) {					
					InventoryOrder order = inventoryOrderDAOImpl.retrieveOrder(Integer.valueOf(orderId));
					list.add(order);
				}
			}
			
			JinSuanOrderTemplate orderTemplate = new JinSuanOrderTemplate(list, templatePosition);

			wb = orderTemplate.processList();

			ByteArrayOutputStream os = new ByteArrayOutputStream();
			try {
				wb.write(os);
			} catch (IOException e) {
				loggerLocal.error(e);
			}
			byte[] content = os.toByteArray();
			byteArrayInputStream = new ByteArrayInputStream(content);
			returnMap.put("stream", byteArrayInputStream);

			return returnMap;
		} catch (Exception ex) {
			loggerLocal.error(ex);
		}
		return null;
	}

	/**
	 * 生成pda订单，
	 * 
	 * @param order
	 * @param string orderType 0: by category 1: by brand
	 * @return
	 */
	@Transactional
	public Map<String, Object> generatePDAOrder(InventoryOrder order, String templatePosition, int orderType) {
		Map<String, Object> returnMap = new HashMap<String, Object>();

		ByteArrayInputStream byteArrayInputStream;
		try {
			HSSFWorkbook wb = null;

			// to get the order information from database
			order = inventoryOrderDAOImpl.retrieveOrder(order.getOrder_ID());

			// 获取库存
			int inventory = 0;
			Map<String, Integer> inventoryMap = new HashMap<String, Integer>();

			Set<InventoryOrderProduct> productsBarcodes = order.getProduct_Set();
			for (InventoryOrderProduct product : productsBarcodes) {
				inventory = headQInventoryStockDAOImpl.getProductStock(product.getProductBarcode().getId(), order.getStore().getId(), true);

				inventoryMap.put(product.getProductBarcode().getBarcode(), inventory);
			}

			if (orderType == 0) {
				PDAOrderTemplate orderTemplate = new PDAOrderTemplate(order, templatePosition, inventoryMap);
				wb = orderTemplate.process();
			} else if (orderType == 1) {
				PDAOrderByBrandTemplate orderTemplate = new PDAOrderByBrandTemplate(order, templatePosition,
						inventoryMap);
				wb = orderTemplate.process();
			}

			ByteArrayOutputStream os = new ByteArrayOutputStream();
			try {
				wb.write(os);
			} catch (IOException e) {
				loggerLocal.error(e);
			}
			byte[] content = os.toByteArray();
			byteArrayInputStream = new ByteArrayInputStream(content);
			returnMap.put("stream", byteArrayInputStream);

			return returnMap;
		} catch (Exception ex) {
			loggerLocal.error(ex);
		}
		return null;
	}

	/**
	 * 获取inventory order作为打印的对象
	 * 
	 * @param id
	 * @return
	 * @throws Exception 
	 */
	@Transactional
	public Response printInventoryPDAorder(InventoryOrder order) throws Exception {
		Response response = new Response();
		Map<String, Object> dataMap = new HashMap<String, Object>();

		// 获取库存
		int sortId = 0;
		int inventory = 0;
		int inventorySum = 0;

		if (order == null) {
			response.setFail("无法找到单据, 单据号  : " + order.getOrder_ID());
		} else {
			//确定用户是从edit页面还是view页面打印
			if (order.getProduct_List() == null || order.getProduct_List().size() == 0) {
				order = searchByID(order.getOrder_ID());
			} else {
			   this.save(order);
			   
			   inventoryOrderDAOImpl.evict(order);
			   
			   order = inventoryOrderDAOImpl.retrieveOrder(order.getOrder_ID());
			   
			   order.putSetToList();
			}

			List<HeadqInventoryPDAproductVO> list = new ArrayList<HeadqInventoryPDAproductVO>();

			List<InventoryOrderProduct> products = order.getProduct_List();
			
			Collections.sort(products, new HeadQInventoryOrderProduct4Peihuo());
			
			if (products != null) {
				for (InventoryOrderProduct inventoryOrderProduct : products) {
					if (StringUtils.isNotEmpty(inventoryOrderProduct.getProductBarcode().getBarcode())) {
						inventoryOrderProduct.setOrder(order);
						
						HeadqInventoryPDAproductVO hVo = new HeadqInventoryPDAproductVO();
						sortId +=1;
						hVo.setSortId(sortId);
						hVo.setYear(inventoryOrderProduct.getProductBarcode().getProduct().getYear().getYear() + inventoryOrderProduct.getProductBarcode().getProduct().getQuarter().getQuarter_Name());
						hVo.setBrand(inventoryOrderProduct.getProductBarcode().getProduct().getBrand().getBrand_Name());
						int categoryLevelId = productBarcodeDaoImpl.selectCategoryLevelId(inventoryOrderProduct.getProductBarcode().getBarcode());
						hVo.setCategoryLevel(categoryLevelId);
						String categoryName = productBarcodeDaoImpl
								.selectCategoryByBarcode(inventoryOrderProduct.getProductBarcode().getBarcode());
						hVo.setCategoryName(categoryName);
						hVo.setNumber(inventoryOrderProduct.getQuantity());
						ProductBarcode barcode = productBarcodeDaoImpl.getByBarcode(inventoryOrderProduct.getProductBarcode().getBarcode());
						hVo.setProductIdentity(barcode.getProduct().getProductIdentity());
						hVo.setProductCode(barcode.getProduct().getProductCode());
						
						if (inventoryOrderProduct.getProductBarcode().getColor() != null)
						    hVo.setColor(inventoryOrderProduct.getProductBarcode().getColor().getName());

						//String barcodeString = inventoryOrderProduct.getProductBarcode().getBarcode();

						//系统库存
						inventory = headQInventoryStockDAOImpl.getProductStock(inventoryOrderProduct.getProductBarcode().getId(), order.getStore().getId(), true);

						hVo.setInventoryNum(inventory);

						inventorySum += inventoryOrderProduct.getQuantity();

						list.add(hVo);
					}
				}
			}
			HeadqInventoryPDAorderVO oAorderVO = new HeadqInventoryPDAorderVO();
			oAorderVO.setCustName(order.getClient_name());
			UserInfor userInfor = userInforService.getUser(order.getOrder_scanner().getUser_id(), true);
			oAorderVO.setEnterUserName(userInfor.getName());
			oAorderVO.setNumberSum(inventorySum);
			oAorderVO.setOrderTime(Common_util.dateFormat_f.format(order.getOrder_StartTime()));
			oAorderVO.setHqComment(order.getComment2());	
			oAorderVO.setCustomComment(order.getComment());
//			Collections.sort(list,new Comparator<HeadqInventoryPDAproductVO>() {
//				@Override
//				public int compare(HeadqInventoryPDAproductVO o1, HeadqInventoryPDAproductVO o2) {
//					return o1.getCategoryLevel() - o2.getCategoryLevel();
//				}
//			});						
			oAorderVO.setPdAproductVOs(list);

			dataMap.put("inventoryOrder", oAorderVO);
			response.setReturnValue(dataMap);
		}

		return response;
	}

	/**
	 * to prepare the inventory order uiBean
	 * 
	 * @return
	 * @throws Exception
	 */
	public InventoryOrderActionUIBean prepareUIBean() throws Exception {
		// 1. prepare the user list
		List<UserInfor> users = userInforService.getAllNormalUsers();

		InventoryOrderActionUIBean uiBean = new InventoryOrderActionUIBean();
		uiBean.setUsers(users);

		List<HeadQInventoryStore> stores = new ArrayList<HeadQInventoryStore>();
		stores = headQInventoryStoreDAOImpl.getActiveStores();

		uiBean.setStores(stores);

		return uiBean;
	}

	/**
	 * before search the inventory order
	 * 
	 * @return
	 */
	@SuppressWarnings("static-access")
	public InventoryOrderActionUIBean preparePreSearchUIBean() {
		InventoryOrderActionUIBean uiBean = new InventoryOrderActionUIBean();

		Map<Integer, String> typesMap = InventoryOrder.getTypesMap_wholeSaler();
		Map<Integer, String> orderStatusMap = InventoryOrder.getOrderStatusMap();
		Map<Integer, String> orderTypeMap = InventoryOrder.getTypesMap_wholeSaler();

		//会计
		List<UserInfor> accounts = userInforService.getUsersByDept(UserInfor.ACCOUNTANT_CODE);

		//库房		
		List<HeadQInventoryStore> stores = headQInventoryStoreDAOImpl.getActiveStores();
		stores.add(0, HeadQInventoryStoreDAOImpl.getDummyAllStore());
		uiBean.setStores(stores);

		uiBean.setTypesMap(typesMap);
		uiBean.setOrderStatusMap(orderStatusMap);
		uiBean.setOrderTypeMap(orderTypeMap);
		uiBean.setUsers(accounts);

		return uiBean;
	}

	/**
	 * the function to transfer the excel to inventory order
	 * 
	 * @param orderExcel
	 * @return
	 * @throws IOException
	 */
	public InventoryOrder transferJinSuanToObject(File orderExcel) throws IOException {
		JinSuanOrderTemplate jinSuanOrderTemplate = new JinSuanOrderTemplate(orderExcel);

		InventoryOrder order = jinSuanOrderTemplate.transferExcelToObj();

		Set<String> barcodes = new HashSet<String>();
		List<InventoryOrderProduct> orderProducts = order.getProduct_List();

		// to get the barcodes and transfer to objects
		for (InventoryOrderProduct orderProduct : orderProducts)
			barcodes.add(orderProduct.getProductBarcode().getBarcode());

		List<ProductBarcode> ProductBarcodes = productBarcodeDaoImpl.getProductBarcodes(barcodes);
		HashMap<String, ProductBarcode> proHashMap = new HashMap<String, ProductBarcode>();

		for (ProductBarcode product : ProductBarcodes) {
			proHashMap.put(product.getBarcode(), product);
		}

		// to set the product record
		for (InventoryOrderProduct orderProduct : orderProducts) {
			String barcode = orderProduct.getProductBarcode().getBarcode();
			ProductBarcode productBarcode = proHashMap.get(barcode);
			if (productBarcode != null) {
				Product product = productBarcode.getProduct();

				orderProduct.setProductBarcode(productBarcode);
				orderProduct.setRecCost(product.getRecCost());
				orderProduct.setSalesPrice(product.getSalesPrice());

				// check whether the whole price is changed manually
				calculateSalePriceDiscount(orderProduct, product);
			} else {
				orderProduct.setSalesPrice(0);
				orderProduct.setWholeSalePrice(0);
				orderProduct.setSalesPrice(0);
			}
		}

		return order;
	}

//	private InventoryOrder getById(int order_ID){
//		InventoryOrder order = inventoryOrderDAOImpl.retrieveOrder(order_ID);
//		inventoryOrderDAOImpl.initialize(order);
//		
//		return order;
//	}

	/**
	 * to determine the price selected and discount in the system
	 * 
	 * @param orderProduct
	 * @param product
	 */
	private void calculateSalePriceDiscount(InventoryOrderProduct orderProduct, Product product) {
		// check whether the whole price is changed manually
		double salePriceSelect_import = orderProduct.getSalePriceSelected();
		double wholePrice_import = orderProduct.getWholeSalePrice();

		double wholePrice1 = product.getWholeSalePrice();
		double wholePrice2 = product.getWholeSalePrice2();
		double wholePrice3 = product.getWholeSalePrice3();
		double retailPriceFactory = product.getSalesPriceFactory();

		if (salePriceSelect_import != wholePrice1 && salePriceSelect_import != wholePrice2
				&& salePriceSelect_import != wholePrice3 && salePriceSelect_import != retailPriceFactory) {
			BigDecimal decimal = null;
			double discount = 0;
			if (wholePrice3 != 0) {
				decimal = new BigDecimal(wholePrice_import / wholePrice3);
				discount = decimal.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
				orderProduct.setDiscount(discount);
				orderProduct.setSalePriceSelected(wholePrice3);
			} else if (wholePrice2 != 0) {
				decimal = new BigDecimal(wholePrice_import / wholePrice2);
				discount = decimal.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
				orderProduct.setDiscount(discount);
				orderProduct.setSalePriceSelected(wholePrice2);
			} else if (wholePrice1 != 0) {
				decimal = new BigDecimal(wholePrice_import / wholePrice1);
				discount = decimal.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
				orderProduct.setDiscount(discount);
				orderProduct.setSalePriceSelected(wholePrice1);
			} else if (retailPriceFactory != 0) {
				decimal = new BigDecimal(wholePrice_import / retailPriceFactory);
				discount = decimal.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
				orderProduct.setDiscount(discount);
				orderProduct.setSalePriceSelected(retailPriceFactory);
			} else
				loggerLocal.error("Error to import the product : " + product.getSerialNum() + "," + wholePrice_import
						+ "," + salePriceSelect_import);
		}

	}

	/**
	 * when people type the pinyin, this service will search the client infroamtion
	 * from the jinsuan database
	 * 
	 * @param pinyin
	 * @return
	 */
	public List<ClientsMS> getClients(String pinyin) {
		pinyin = pinyin.replaceAll(" ", "_");

		return clientDAOImpl.getClientByPinyin(pinyin);
	}

	/**
	 * 员工通过pda提交给仓库配货订单 PDA提交
	 * 
	 * @param order
	 * @param loginUserInfor
	 */
	private Response saveToInventory(InventoryOrder order, UserInfor loginUserInfor) {
		Response response = new Response();
		int clientId = order.getClient_id();
		int orderId = order.getOrder_ID();

		ClientsMS client = clientDAOImpl.getClientsByID(clientId);
		if (client == null) {
			response.setQuickValue(Response.ERROR, "请核对客户名字,重新输入");
		} else {

			// part 1. to set the selected price and whole price
			Set<String> barcodes = new HashSet<String>();

			// 1.1 to store the non-duplicated product code in a sequence list for new order
			List<InventoryOrderProduct> orderProducts = order.getProduct_List();
			for (InventoryOrderProduct orderProduct : orderProducts) {
				if (orderProduct != null && orderProduct.getProductBarcode() != null
						&& !orderProduct.getProductBarcode().getBarcode().equals("")) {
					String barcode = orderProduct.getProductBarcode().getBarcode();
					barcodes.add(barcode);
				}
			}

			Map<String, ProductBarcode> productMap = productBarcodeDaoImpl.getProductMapByBarcode(barcodes);

			// 1.2 to set the re-cost, selected price, whole price, discount
			// totalQ, totalWhole, totalRecost, totalSalePrice
			int totalQ = 0;
			double totalWholePrice = 0;
			double totalCost = 0;
			double totalSalePrice = 0;

			for (int i = 0; i < orderProducts.size(); i++) {
				InventoryOrderProduct orderProduct = orderProducts.get(i);
				if (orderProduct == null || orderProduct.getProductBarcode() == null)
					continue;
//				
//				if (orderProduct.getQuantity() == 0)
//					orderProducts.remove(i);

				String barcode = orderProduct.getProductBarcode().getBarcode();
				ProductBarcode productBarcode = productMap.get(barcode);

				if (productBarcode == null) {
					loggerLocal.error("Error to get the product barcode information :" + barcode);
				} else {
					Product product = productBarcode.getProduct();

					double selectedPrice = productBarcodeDaoImpl.getSelectedSalePrice(productBarcode);
					double discount = 1;
					if (selectedPrice == product.getSalesPriceFactory())
						discount = product.getDiscount();

					int quantity = orderProduct.getQuantity();
					double wholePrice = selectedPrice * discount;
					double cost = product.getRecCost();
					double salePrice = product.getSalesPrice();

					orderProduct.setDiscount(discount);
					orderProduct.setSalePriceSelected(selectedPrice);
					orderProduct.setWholeSalePrice(Common_util.roundDouble(wholePrice, 2));
					orderProduct.setSalesPrice(salePrice);
					orderProduct.setProductBarcode(productBarcode);
					orderProduct.setRecCost(cost);

					totalQ += quantity;
					totalCost += quantity * cost;
					totalWholePrice += wholePrice * quantity;
					totalSalePrice += salePrice * quantity;
				}

			}

			order.setPdaScanner(loginUserInfor);
			order.setOrder_scanner(loginUserInfor);
			order.setClient_name(client.getName() + "," + client.getRegion().getName());
			order.setComment("");
			order.setOrder_StartTime(new Date());
			order.setOrder_type(InventoryOrder.TYPE_SALES_ORDER_W);
			order.setTotalQuantity(totalQ);
			order.setTotalRecCost(Common_util.roundDouble(totalCost, 2));
			order.setTotalRetailPrice(Common_util.roundDouble(totalSalePrice, 2));
			order.setTotalWholePrice(Common_util.roundDouble(totalWholePrice, 2));

			save(order);

			response.setQuickValue(Response.SUCCESS, "");
		}

		return response;
	}

	/**
	 * the person use the PDA to do the order recording and submit to inventory
	 * PDA提交仓库
	 * 
	 * @param order
	 * @param loginUserInfor
	 */
	@Transactional
	public Response pdaSaveToInventory(InventoryOrder order, UserInfor loginUserInfor) {
		order.setOrder_Status(InventoryOrder.STATUS_PDA_COMPLETE);
		return saveToInventory(order, loginUserInfor);
	}

	/**
	 * the person use the PDA to do the order recording and submit to inventory
	 * PDA提交草稿
	 * 
	 * @param order
	 * @param loginUserInfor
	 */
	@Transactional
	public Response pdaSaveToDraft(InventoryOrder order, UserInfor loginUserInfor) {
		order.setOrder_Status(InventoryOrder.STATUS_PDA_DRAFT);
		return saveToInventory(order, loginUserInfor);
	}

	/**
	 * the inventory person edit the orders completed by PDA person
	 * 
	 * @param order_ID
	 * @param loginUserInfor
	 * @return
	 */
	@Transactional
	public InventoryOrder editPDAComplete(int order_ID, UserInfor loginUserInfor) {
		InventoryOrder order = searchByID(order_ID);
//		order.setOrder_Status(InventoryOrder.STATUS_DRAFT);
//		order.setOrder_Keeper(loginUserInfor);
//
//		inventoryOrderDAOImpl.update(order, true);

		return order;
	}

	/**
	 * 获取当前order， action : 1 -> edit page 2 -> display page
	 * 
	 * @param orderId
	 * @param loginUserInfor
	 * @return
	 */
	@Transactional
	public Response loadOrder(int orderId, UserInfor loginUserInfor) {
		Response response = new Response();

		InventoryOrder order = inventoryOrderDAOImpl.get(orderId, false);
		if (order == null) {
			response.setQuickValue(Response.FAIL, "数据库无法找到,单据" + orderId);
		} else {

			int status = order.getOrder_Status();
			switch (status) {
			case InventoryOrder.STATUS_DELETED:
				response.setQuickValue(Response.FAIL, "单据(" + orderId + ") 处于删除状态,无法开启。请联系管理员");
				break;
			case InventoryOrder.STATUS_PDA_COMPLETE:
				order = editPDAComplete(orderId, loginUserInfor);
				response.setReturnValue(order);
				response.setAction(2);
				response.setReturnCode(Response.SUCCESS);
				break;
			case InventoryOrder.STATUS_COMPLETE:
				order = searchByID(orderId);
				order.setOrder_Auditor(loginUserInfor);
				order.setOrder_Status(InventoryOrder.STATUS_ACCOUNT_PROCESS);
				inventoryOrderDAOImpl.update(order, false);
				response.setAction(2);
				response.setReturnValue(order);
				response.setReturnCode(Response.SUCCESS);
				break;
			case InventoryOrder.STATUS_DRAFT:
				order = searchByID(orderId);
				UserInfor keeper = order.getOrder_Keeper();
				if (keeper.getUser_id() != loginUserInfor.getUser_id()) {
					response.setQuickValue(Response.FAIL,
							"单据(" + orderId + ") 正在被 " + keeper.getName() + " 修改,你暂时无法修改");
				} else {
					response.setAction(1);
					response.setReturnValue(order);
					response.setReturnCode(Response.SUCCESS);
				}
				break;
			case InventoryOrder.STATUS_ACCOUNT_PROCESS:
				order = searchByID(orderId);
				UserInfor auditor2 = order.getOrder_Auditor();
				if (auditor2 != null && auditor2.getUser_id() != loginUserInfor.getUser_id()) {
					response.setQuickValue(Response.FAIL,
							"单据(" + orderId + ") 正在被 " + auditor2.getName() + " 修改,你暂时无法修改");
				} else {
					if (auditor2 == null) {
						order.setOrder_Auditor(loginUserInfor);
						inventoryOrderDAOImpl.update(order, false);
					}
					response.setAction(2);
					response.setReturnValue(order);
					response.setReturnCode(Response.SUCCESS);
				}
				break;
			case InventoryOrder.STATUS_ACCOUNT_COMPLETE:
			case InventoryOrder.STATUS_CANCELLED:
			case InventoryOrder.STATUS_WAITING_AUDIT:
				order = searchByID(orderId);
				response.setAction(2);
				response.setReturnValue(order);
				response.setReturnCode(Response.SUCCESS);
				break;
			default:
				response.setQuickValue(Response.FAIL, "无法找到对应的资源(当前单据可能已经被其他人占用)，请刷新然后继续搜索");
				break;
			}
		}

		return response;
	}

	public ClientsMS getClients(int clientId) {
		return clientDAOImpl.getClientsByID(clientId);
	}

	/**
	 * service function to get the PDA drafts
	 * 
	 * @param loginUserInfor
	 * @return
	 */
	public List<InventoryOrder> getPDADrafts(UserInfor loginUserInfor) {
		DetachedCriteria criteria = DetachedCriteria.forClass(InventoryOrder.class, "order");
		criteria.add(Restrictions.eq("order.pdaScanner.user_id", loginUserInfor.getUser_id()));
		criteria.add(Restrictions.eq("order.order_Status", InventoryOrder.STATUS_PDA_DRAFT));

		return inventoryOrderDAOImpl.getByCritera(criteria, false);
	}

	/**
	 * to get the pda draft order by id
	 * 
	 * @param loginUserInfor
	 * @param order_ID
	 * @return
	 */
	@Transactional
	public InventoryOrder getPDADraft(UserInfor loginUserInfor, int order_ID) {
		InventoryOrder order = inventoryOrderDAOImpl.retrieveOrder(order_ID);
		if (order == null)
			order = new InventoryOrder();

		order.putSetToList();

		Collections.reverse(order.getProduct_List());

		return order;
	}

	/**
	 * 准备搜索时的vo map
	 * 
	 * @param orderList
	 * @param user
	 * @return
	 */
	public Map constructInventoryOrderVOMap(List<InventoryOrder> orderList, UserInfor user) {
		Map data = new HashMap<String, Object>();
		List<InventoryOrderVO> inventoryOrderVOs = new ArrayList<InventoryOrderVO>();
		Integer sumNumber = 0;
		double sumWholesale = 0;
				
		if (orderList != null) {
			for (InventoryOrder order : orderList) {
				boolean isEditable = false;
				boolean isTranferable = false;
				sumNumber += order.getTotalQuantity();
				sumWholesale += order.getTotalWholePrice();
				int orderStatus = order.getOrder_Status();
				switch (orderStatus) {
				case InventoryOrder.STATUS_DRAFT:
					if (user.equals(order.getOrder_Keeper()) && user.containFunction("inventoryOrder!editDraft"))
						isEditable = true;
					else if ((order.getOrder_Keeper() == null || order.getOrder_Keeper().getUser_id() == 0)
							&& user.containFunction("inventoryOrder!editDraft"))
						isEditable = true;

					if (user.equals(order.getOrder_Keeper()))
						isTranferable = true;
					break;
				case InventoryOrder.STATUS_ACCOUNT_PROCESS:
					if (user.containFunction("inventoryOrder!acctUpdate")) {
						if (user.equals(order.getOrder_Auditor())
								|| (order.getOrder_Auditor() == null || order.getOrder_Auditor().getUser_id() == 0))
							isEditable = true;
					}
					if (user.equals(order.getOrder_Auditor()))
						isTranferable = true;

					break;
				case InventoryOrder.STATUS_WAITING_AUDIT:
					if (user.containFunction("inventoryOrderJSON!acctAuditOrder"))
						isEditable = true;
					isTranferable = false;
					break;
				case InventoryOrder.STATUS_ACCOUNT_COMPLETE:
					isEditable = true;
					isTranferable = false;
					break;
				case InventoryOrder.STATUS_CANCELLED:
					isEditable = true;
					isTranferable = false;
					break;
				case InventoryOrder.STATUS_PDA_COMPLETE:
					if (user.containFunction("inventoryOrder!editDraft"))
						isEditable = true;

					isTranferable = false;
					break;
				default:
					break;
				}

				InventoryOrderVO vo = new InventoryOrderVO(order);
				vo.setIsAuthorizedToEdit(isEditable);
				vo.setIsAuthorizedToTransfer(isTranferable);
				inventoryOrderVOs.add(vo);
			}
		}
		InventoryOrderVO vo = new InventoryOrderVO();
		vo.setClientName("合计");
		vo.setTotalQ(sumNumber);
		vo.setTotalWholeSales(sumWholesale);
		inventoryOrderVOs.add(vo);

		data.put("rows", inventoryOrderVOs);
		return data;
	}

	/**
	 * 更新order 的 comment
	 * 
	 * @param order
	 * @return
	 */
	public Response updateOrderComment(InventoryOrder order) {
		Response response = new Response();

		if (order != null && order.getOrder_ID() != 0) {
			String hql_order = "UPDATE InventoryOrder i set i.comment = ?, i.comment2 = ?, i.isDaimai=?, i.isMaiduan=?, i.isTransfer=? where order_ID = ?";
			Object[] values = { order.getComment(), order.getComment2(), order.getIsDaimai(), order.getIsMaiduan(),
					order.getIsTransfer(), order.getOrder_ID() };
			inventoryOrderDAOImpl.executeHQLUpdateDelete(hql_order, values, true);
			response.setSuccess("成功更新备注");
		} else {
			response.setFail("无法找到当前订单号");
		}

		return response;
	}

	/**
	 * 将单据权限转移给其他人
	 * 
	 * @param order_ID
	 * @param loginUserInfor
	 * @param user
	 * @return
	 */
	public Response transferOrderToOther(int orderId, UserInfor loginUserInfor, UserInfor user) {
		Response response = new Response();

		InventoryOrder order = inventoryOrderDAOImpl.get(orderId, true);
		if (order == null) {
			response.setQuickValue(Response.FAIL, "数据库无法找到,单据" + orderId);
		} else {

			int status = order.getOrder_Status();
			switch (status) {
			case InventoryOrder.STATUS_DELETED:
				response.setQuickValue(Response.FAIL, "单据" + orderId + " 处于删除状态,无法开启。请联系管理员");
				break;
			case InventoryOrder.STATUS_PDA_COMPLETE:
			case InventoryOrder.STATUS_ACCOUNT_COMPLETE:
			case InventoryOrder.STATUS_CANCELLED:
				response.setQuickValue(Response.FAIL, "单据" + orderId + " 处于任何人都能查看状态,无需转移权限");
				break;

			case InventoryOrder.STATUS_DRAFT:
				UserInfor orderKeeper = order.getOrder_Keeper();
				if (orderKeeper.getUser_id() != loginUserInfor.getUser_id()) {
					response.setQuickValue(Response.FAIL, "你没有修改单据的权限");
				} else {
					order.setOrder_Keeper(user);
					inventoryOrderDAOImpl.update(order, true);
				}
				break;
			case InventoryOrder.STATUS_ACCOUNT_PROCESS:
				UserInfor orderUser = order.getOrder_Auditor();
				if (orderUser.getUser_id() != loginUserInfor.getUser_id()) {
					response.setQuickValue(Response.FAIL, "你没有修改单据的权限");
				} else {
					order.setOrder_Auditor(user);
					inventoryOrderDAOImpl.update(order, true);
				}
				break;

			default:
				response.setQuickValue(Response.FAIL, "无法找到对应的资源，请刷新然后继续搜索");
				break;
			}
		}

		return response;
	}

	/**
	 * 获取inventory order作为打印的对象
	 * 
	 * @param id
	 * @return
	 */
	@Transactional
	public Response getInventoryOrderForPrint(int id) {
		Response response = new Response();
		Map<String, Object> dataMap = new HashMap<String, Object>();

		InventoryOrder order = inventoryOrderDAOImpl.retrieveOrder(id);
		if (order == null) {
			response.setFail("无法找到单据, 单据号  : " + id);
		} else {
			order.putSetToList();

			// todo
			double preAcctAmt = this.calculatePreAcctBalance(order.getClient_id());

			double postAcctAmt = this.calculatePostAcctBalance(order, preAcctAmt);

			InventoryOrderPrintVO inventoryOrderPrintVO = new InventoryOrderPrintVO(order, preAcctAmt, postAcctAmt);
			dataMap.put("inventoryOrder", inventoryOrderPrintVO);

			response.setReturnValue(dataMap);
		}

		return response;
	}

	private double calculatePreAcctBalance(int clientId) {
		HeadQCust cust = headQCustDaoImpl.get(clientId, true);

		// 2.update the order's preAcctAmt and postAcctAmt

		double initialAcctAmt = 0;
		if (cust != null)
			initialAcctAmt = cust.getInitialAcctBalance();

		double acctAmtFlow = chainAcctFlowDaoImpl.getAcctFlowByCustId(clientId);
		double preAcctAmt = Common_util.getDecimalDouble(initialAcctAmt + acctAmtFlow);


		return preAcctAmt;
	}

	private double calculatePostAcctBalance(InventoryOrder order, double preAcctAmt) {
		int orderType = order.getOrder_type();

		if (orderType == InventoryOrder.TYPE_SALES_FREE_ORDER_W)
			return preAcctAmt;

		double totalAmt = order.getTotalWholePrice();
		double totalDis = order.getTotalDiscount();
		double netAmt = totalAmt - totalDis;
		// 1. update the offset
		int offset = 1;
		if (orderType == InventoryOrder.TYPE_SALES_RETURN_ORDER_W)
			offset *= -1;

		netAmt *= offset;

		double postAcctAmt = Common_util.getDecimalDouble(
				preAcctAmt + netAmt - order.getCash() - order.getCard() - order.getAlipay() - order.getWechat());

		return postAcctAmt;
	}

	/**
	 * 获取当前产品的采购价 1. 优先拿历史采购成本价 2. recCost2 3. recCost
	 * 
	 * @param pbId
	 * @return
	 */
	private double getProductBarcodeCost(int pbId) {
		HeadqPurchaseHistory history = headqPurchaseHistoryDaoImpl.get(pbId, true);
		if (history != null)
			return history.getRecCost();
		else {
			ProductBarcode pb = productBarcodeDaoImpl.get(pbId, true);
			double cost2 = pb.getProduct().getRecCost2();
			if (cost2 > 0)
				return cost2;
			else
				return pb.getProduct().getRecCost();
		}
	}


	


	/**
	 * 下载销售单据
	 * @param path
	 * @param list
	 * @return
	 */
	public Response generateHqSaleExcel(String path,List<InventoryOrderVO> list) {
		Response response = new Response();
		try {			
			InventoryOrderTemplate reportTemplate = new InventoryOrderTemplate(path, list);
			HSSFWorkbook wb = reportTemplate.processSale();
			ByteArrayInputStream byteArrayInputStream = ExcelUtil.convertExcelToInputStream(wb);

			response.setReturnValue(byteArrayInputStream);
			response.setReturnCode(Response.SUCCESS);
		} catch (Exception e) {
			loggerLocal.error(e);
			e.printStackTrace();
			response.setFail(e.getMessage());
		}
		return response;
	}
	
	/**
	 * 填补某个时间段的批发销售，批发采购单据的库存
	 * @return
	 */
	@Transactional
	public Response checkDummyOrders() {
		Response response = new Response();
		/**
		 * 批发销售
		 */
		DetachedCriteria criteria = DetachedCriteria.forClass(InventoryOrder.class, "order");

		criteria.add(Restrictions.eq("order.order_Status", InventoryOrder.STATUS_ACCOUNT_COMPLETE));
		Calendar calendar = Calendar.getInstance();
		calendar.set(Calendar.MONTH, 0);
		calendar.set(Calendar.DATE,1);
        calendar.set(Calendar.HOUR, 0);
		java.sql.Date startDate = new java.sql.Date(calendar.getTimeInMillis());

//		Calendar calendar2 = Calendar.getInstance();
//		calendar2.set(Calendar.MONTH, 0);
//		calendar2.set(Calendar.DATE,2);
//        calendar2.set(Calendar.HOUR, 0);
//		java.sql.Date endTime = new java.sql.Date(calendar2.getTimeInMillis());
		
		Date endTime = Common_util.getToday();
        criteria.add(Restrictions.between("order.order_StartTime", startDate,endTime));

        List<InventoryOrder> orders = inventoryOrderDAOImpl.getByCritera(criteria, true);
        for (InventoryOrder order: orders) {
        	loggerLocal.info("更新库存  销售单据: " + order.getOrder_ID() + "," + order.getClient_name());
        	inventoryOrderDAOImpl.initialize(order);
        	try {
        	   this.updateHeadqInventory(order, false);
        	} catch (Exception e) {
        		loggerLocal.error(e);
        		loggerLocal.info("*****更新库存  销售单据出错: " + order.getOrder_ID() + "," + order.getClient_name());
			}
        }
		
        /**
         * 采购单据
         */
        DetachedCriteria criteriaPurchase = DetachedCriteria.forClass(PurchaseOrder.class,"order");
        criteriaPurchase.add(Restrictions.eq("order.status", PurchaseOrder.STATUS_COMPLETE));
        criteriaPurchase.add(Restrictions.between("order.creationTime",startDate,endTime));
        List<PurchaseOrder> purchaseOrders = PurchaseOrderDaoImpl.getByCritera(criteriaPurchase, true);
		for (PurchaseOrder order: purchaseOrders) {
        	loggerLocal.info("更新库存  采购单据: " + order.getId() + "," + order.getSupplier().getName());
        	PurchaseOrderDaoImpl.initialize(order);
        	try {
        	    purchaseService.updateHeadqInventory(order, false);
        	} catch (Exception e) {
        		loggerLocal.error(e);
        		loggerLocal.info("*****更新库存  采购单据出错: " + order.getId() + "," + order.getSupplier().getName());
			}
		}
		return response;
	}

	/**
	 * 查询PDA单据的草稿
	 * @param formBean
	 * @return
	 */
	public Response getPDAOrder4StoreMB(InventoryOrderActionFormBean formBean, UserInfor logninUser, int dateOff) {
		Response response = new Response();
		
		DetachedCriteria criteria = DetachedCriteria.forClass(InventoryOrder.class, "order");

		InventoryOrder searchBean = formBean.getOrder();

		Set<Integer> pdaStatuSet  = new HashSet<Integer>();
		pdaStatuSet.add(InventoryOrder.STATUS_PDA_DRAFT);
		pdaStatuSet.add(InventoryOrder.STATUS_PDA_COMPLETE);
		criteria.add(Restrictions.in("order.order_Status", pdaStatuSet));
		
		
		Date today = new Date();
        Date searchDate = Common_util.calcualteDate(today, dateOff);
        criteria.add(Restrictions.between("order.order_StartTime", Common_util.formStartDate(today), Common_util.formEndDate(searchDate)));
        
		if (searchBean.getCust().getId() != 0) {
			int clientid = searchBean.getClient_id();
			criteria.add(Restrictions.eq("order.client_id", clientid));
		} 
		
		List<InventoryOrder> orders = inventoryOrderDAOImpl.search(criteria);
		
		response.setReturnValue(orders);
		
		return response;
	}


	/**
	 * 获取待配单据
	 * @return
	 * @throws ParseException
	 */
	public Response getListPdaOrders(int custRange) throws ParseException {
		Response response = new Response();
		
		Set<Integer> statusSet = new HashSet<Integer>();
		statusSet.add(InventoryOrder.STATUS_PDA_COMPLETE);
		statusSet.add(InventoryOrder.STATUS_PEIHUO_INPROCESS);
		
		List<InventoryOrder> list = inventoryOrderDAOImpl.searchPDAOrdersByStatus(statusSet, custRange, Common_util.getLastWeekDate(), Common_util.getToday());
		List<IpadPdaVO> vos = convertInventoryOrder2IpadPDAVO(list);
		
		Map dataMap = new HashMap();
		dataMap.put("rows", vos);

		response.setReturnValue(dataMap);
		response.setReturnCode(Response.SUCCESS);
		return response;
	}
	
	
	/**
	 * 查询所有配货完成单据
	 * @return
	 * @throws ParseException 
	 */
	public Response getListPdaAlreadOrders(int custRange) throws ParseException {
		Response response = new Response();

		Set<Integer> statusSet = new HashSet<Integer>();
		statusSet.add(InventoryOrder.STATUS_PEIHUO_COMPLETE);
		
		List<InventoryOrder> list = inventoryOrderDAOImpl.searchPDAOrdersByStatus(statusSet, custRange, Common_util.getToday(), Common_util.getToday());
		
		List<IpadPdaVO> vos = convertInventoryOrder2IpadPDAVO(list);
		
		Map dataMap = new HashMap();
		dataMap.put("rows", vos);

		response.setReturnValue(dataMap);
		response.setReturnCode(Response.SUCCESS);
		return response;
	}
	
	@Autowired
	private HeadQEntityTagDaoImpl headQEntityTagDaoImpl;
	
	/**
	 * 转换方法 
	 * @param list
	 * @return
	 */
	private List<IpadPdaVO> convertInventoryOrder2IpadPDAVO(List<InventoryOrder> list){
		List<IpadPdaVO> vos = new ArrayList<IpadPdaVO>();
		
		if (list.size() !=0) {
			
			//优化性能
			String orderIdSet = "(0";
			for (InventoryOrder inventoryOrder : list) {
				orderIdSet +="," + inventoryOrder.getOrder_ID();
			}
			orderIdSet +=")";
			
			Map<Integer, Integer> completeNums = inventoryOrderProductDAOImpl.selectCompleteNums(orderIdSet);

			for (InventoryOrder inventoryOrder : list) {
				IpadPdaVO vo = new IpadPdaVO();
				
				loadIpadPdaVO(vo,inventoryOrder, completeNums);
				vos.add(vo);
//				if (inventoryOrder.getClient_id() !=0) {
//					//可以查看的单据范围
//					int range = (int) ActionContext.getContext().getSession().get(Common_util.IPAD_DISTRIBUTION_SELECT_RANGE);
//					if (range == Common_util.ALL__RANGE) {
//						loadIpadPdaVO(vo,inventoryOrder, completeNums);
//						vos.add(vo);
//					}else if (range == Common_util.QX_RANGE) {
//						HeadqEntityTag entityTag = headQEntityTagDaoImpl.selectEntityTag(inventoryOrder.getClient_id(), HeadQTag.HEADQ_QX_CUST_TAG_ID);
//						if (entityTag != null) {
//							loadIpadPdaVO(vo,inventoryOrder, completeNums);
//							vos.add(vo);
//						}
//					}else if (range == Common_util.XLC_RANGE) {
//						HeadqEntityTag entityTag = headQEntityTagDaoImpl.selectEntityTag(inventoryOrder.getClient_id(), HeadQTag.HEADQ_XLC_CUST_TAG_ID);
//						if (entityTag != null) {
//							loadIpadPdaVO(vo,inventoryOrder, completeNums);
//							vos.add(vo);
//						}
//					}
//									
//				}	
				
			}
		}
		
		return vos;
	}
	
	
	/**
	 * 装填vo
	 * @param vo
	 * @param inventoryOrder
	 */
	private void loadIpadPdaVO(IpadPdaVO vo,InventoryOrder inventoryOrder,Map<Integer, Integer> completeNumsMap ) {
		vo.setId(inventoryOrder.getOrder_ID());
		vo.setCustName(inventoryOrder.getClient_name());
		vo.setComment(inventoryOrder.getComment2());
		vo.setSnums(inventoryOrder.getTotalQuantity());
		//已配数量
		int completeNums = completeNumsMap.get(inventoryOrder.getOrder_ID());
		
		vo.setNoNums(inventoryOrder.getTotalQuantity()-(int)completeNums);
		double completeRate  = (double)completeNums/(double)vo.getSnums();
		vo.setProgress((int) (Common_util.getFormatDouble(completeRate)*100));
		if(inventoryOrder.getOrder_Keeper() != null) {
			vo.setDistributionUser(inventoryOrder.getOrder_Keeper().getUser_name());
		}	
		vo.setStatus(inventoryOrder.getOrder_Status());
		vo.setOrderStartDateS(Common_util.dateFormat_f.format(inventoryOrder.getOrder_StartTime()).substring(5,16));
	}

	/**
	 * 获取配货单
	 * @param orderId
	 * @return
	 */
	public Response getPeihuoOrderById(int orderId) {
		Response response = new Response();
		List<IpadPdaOrderDetailsVO> vos = new ArrayList<IpadPdaOrderDetailsVO>();
		List<InventoryOrderProduct> list = inventoryOrderProductDAOImpl.selectProductsByOrderId(orderId);
		
		Collections.sort(list, new HeadQInventoryOrderProduct4Peihuo());
		
		if (list.size()!=0) {
			for (InventoryOrderProduct inventoryOrderProduct : list) {
				IpadPdaOrderDetailsVO vo = new IpadPdaOrderDetailsVO();
				vo.setPbId(inventoryOrderProduct.getProductBarcode().getId());				
				String phoneUrlPath = picDaoImpl.getURLPathByBarcode(inventoryOrderProduct.getProductBarcode().getBarcode(), ProductBarcodePic.TYPE_PING_MIAN_PIC);
				vo.setImgUrl(phoneUrlPath);// 图片路径
				vo.setYearInfo(inventoryOrderProduct.getProductBarcode().getProduct().getYear().getYear()+inventoryOrderProduct.getProductBarcode().getProduct().getQuarter().getQuarter_Name());
				
				String productIdentity = inventoryOrderProduct.getProductBarcode().getProduct().getProductIdentity();
				if (inventoryOrderProduct.getProductBarcode().getColor() != null)
					productIdentity += " " + inventoryOrderProduct.getProductBarcode().getColor().getName();
				vo.setProductInfo(productIdentity);
				vo.setCategory(inventoryOrderProduct.getProductBarcode().getProduct().getCategoryLevel1().getCategory_Name() +inventoryOrderProduct.getProductBarcode().getProduct().getCategory().getCategory_Name());
				vo.setNumPreHand(inventoryOrderProduct.getProductBarcode().getProduct().getNumPerHand());
				vo.setSnums(inventoryOrderProduct.getQuantity());
				vo.setNums(inventoryOrderProduct.getQuantityPeihuo());
				vo.setProductCode(inventoryOrderProduct.getProductBarcode().getProduct().getProductCode());
				int progress  = (int) (Common_util.getFormatDouble((double)vo.getNums()/(double)vo.getSnums())*100);
				vo.setProgress(progress);
				//stock库存
				int inventoryNums = headQInventoryStockDAOImpl.getInventory(inventoryOrderProduct.getProductBarcode().getId());
				//仓库草稿、待审核,会计录入中
				int nums = inventoryOrderProductDAOImpl.selectQuantiy(inventoryOrderProduct.getProductBarcode().getId());
				//配货中
				int peihuoNums = inventoryOrderProductDAOImpl.selectIpadNoEquidppedNums(inventoryOrderProduct.getProductBarcode().getId(),InventoryOrder.STATUS_PEIHUO_INPROCESS);
			
				vo.setInventoryNums(inventoryNums-nums-peihuoNums);
				vos.add(vo);
			}
		}

		Map dataMap = new HashMap();
		
		
		
		dataMap.put("rows", vos);

		response.setReturnValue(dataMap);
		response.setReturnCode(Response.SUCCESS);
		return response;
	}

	/**
	 * 获取客户端，客户当前库存是多少
	 * @param clientId
	 * @param barcode
	 * @return
	 */
	public Response checkClientInventory(int clientId, String barcode) {
		Response response = new Response();
		if (clientId == 0) {
			response.setFail("客户ID为0,无法查找");
			return response;
		} 
		
		ChainStore chainStore = chainStoreDaoImpl.getByClientId(clientId);
		if (chainStore == null) {
			response.setFail("当前客户ID " + clientId + ",是非连锁店客户,无法查找库存");
			return response;
		}
		
		ProductBarcode pBarcode = productBarcodeDaoImpl.getByBarcode(barcode);
		if (pBarcode == null) {
			response.setFail("当前产品信息 " + barcode + "无法在数据库找到");
			return response;
		}
		
		// 1. 检查客户是否已经验收了
		String url = SystemParm.getParm("CHAIN_INVENTORY_SERVICE");
		// 要传的参数
		String s = null;
		String result = null;
		try {
			//s = URLEncoder.encode("formBean.order.cust.id", "UTF-8") + "=" + clientId;
			//s += URLEncoder.encode("&formBean.productId", "UTF-8") + "=" + pBarcode.getId();
            //s += URLEncoder.encode("&formBean.serviceId", "UTF-8") + "=2";
			s="formBean.order.cust.id="+clientId+"&formBean.productId="+pBarcode.getId()+"&formBean.serviceId=2";
			result = HttpUtil.callRemoteService(url, s);

			JSONObject jsonObject = JSONObject.fromObject(result);

			Response response2 = (Response) JSONObject.toBean(jsonObject, Response.class);
			if (response2.getReturnCode() == Response.SUCCESS) {
				Object returnValue = response2.getReturnValue();
				jsonObject = JSONObject.fromObject(returnValue);
				InventoryOrderVO inventoryOrderVO = (InventoryOrderVO) JSONObject.toBean(jsonObject,
						InventoryOrderVO.class);
				
				String msgString = "客户名字 : " + inventoryOrderVO.getClientName() + "<br>";
				       msgString += "货品信息 : " + inventoryOrderVO.getComment()  + "<br>";
				       msgString += "当前客户库存 : " + inventoryOrderVO.getCurrentInventory()  + "<br>";
				       msgString += "客户未确认库存 : " + inventoryOrderVO.getInventoryOnWay()  + "<br>";
				response.setSuccess(msgString);
				
				return response;
			} else {
				response.setQuickValue(Response.FAIL, response2.getMessage());
				return response;
			}
		} catch (Exception e) {
			e.printStackTrace();
			response.setFail("检查远程服务器数据失败，请联系管理员 : " + e.getMessage());
			return response;
		}

	}

	/**
	 * 平板配货初始化单据信息
	 * action 1: Edit
	 * action 2: view
	 * @param formBean
	 */
	@Transactional
	public Response loadPeihuoOrder(IpadActionFormBean formBean,SessionInfo sessionInfo) {
		Response response = new Response();
		InventoryOrder order = inventoryOrderDAOImpl.get(formBean.getOrderId(), true);
		IpadPdaVO vo = new IpadPdaVO();
		if (order != null) {
			vo.setId(order.getOrder_ID());
//			if (order.getClient_id() !=0) {
//				HeadQCust cust = headQCustDaoImpl.get(order.getClient_id(), true);
//				if (cust != null) {
//					vo.setCustName(cust.getName());
//				}					
//			}			
			vo.setCustName(order.getClient_name());
			vo.setComment(order.getComment2());
			vo.setSnums(order.getTotalQuantity());
			//已配数量
			long completeNums = inventoryOrderProductDAOImpl.selectCompleteNums(order.getOrder_ID());
			vo.setCompleteNums((int)completeNums);
			vo.setNoNums(order.getTotalQuantity()-(int)completeNums);
			double completeRate  = (double)completeNums/(double)vo.getSnums();
			vo.setProgress((int) (Common_util.getFormatDouble(completeRate)*100));


			
			switch (order.getOrder_Status()) {
			   case InventoryOrder.STATUS_PDA_COMPLETE:
					UserInfor userInfor = userInforService.getUser(sessionInfo.getUserId(), true);
					order.setOrder_Status(InventoryOrder.STATUS_PEIHUO_INPROCESS);
					order.setOrder_Keeper(userInfor);
					inventoryOrderDAOImpl.update(order, true);
					
				   response.setAction(1);
				   break;
			   case InventoryOrder.STATUS_PEIHUO_INPROCESS:
			   case InventoryOrder.STATUS_PEIHUO_COMPLETE:
				   if (order.getOrder_Keeper().getUser_id() != sessionInfo.getUserId())
					   response.setAction(2);
				   else 
				       response.setAction(1);
				   break;
			   default:
				   response.setFail("单据状态出现问题: " + formBean.getOrderId() + "," + order.getOrder_Status());
				   break;
			}
			
			vo.setStatusS(order.getOrder_Status_s());
			vo.setStatus(order.getOrder_Status());
			formBean.setIpadPdaVO(vo);
			
			vo.setDistributionUser(order.getOrder_Keeper().getUser_name());
		} else {
			response.setFail("无法找到单据 : " + formBean.getOrderId());
		}
		
		return response;
	}
	
	
	/**
	 * 根据单据id和货品id,修改货品配货数量
	 * @param orderId
	 * @param pbId
	 * @param quantity
	 * @return
	 */
	@Transactional
	public Response updateInventoryOrderProduct(int rowIndex,int orderId, int pbId, int quantity,int isCheck,SessionInfo sessionInfo) {
		Response response = new Response();
		InventoryOrder order = inventoryOrderDAOImpl.get(orderId, true);
		InventoryOrderProduct orderProduct = inventoryOrderProductDAOImpl.getByOrderIdProductId(orderId, pbId);
		if (orderProduct != null) {
			//1.验证权限
			UserInfor keepUser  = orderProduct.getOrder().getOrder_Keeper();
			if (sessionInfo.getUserId() != keepUser.getUser_id()) {
				response.setFail("此单据配货人员为："+keepUser.getUser_name()+",其他人员无权配货");
				return response;
			}						
			//2.校验数量
			if (quantity>orderProduct.getQuantity()) {
				response.setFail("公司货号："+orderProduct.getProductBarcode().getId()+"选货数量为："+orderProduct.getQuantity()+",已配数量为"+orderProduct.getQuantityPeihuo()+",选货数量不能大于配货数量");
				return response;
			}else if (quantity <0) {
				response.setFail("公司货号："+orderProduct.getProductBarcode().getId()+",配货数量不能小于选货小于0");
				return response;
			}else {
				orderProduct.setQuantityPeihuo(quantity);
				inventoryOrderProductDAOImpl.update(orderProduct, true);
				IpadPeiHuoVO peiHuoVO = new IpadPeiHuoVO();
				peiHuoVO.setPbId(pbId);
				peiHuoVO.setQuantityPeihuo(quantity);
				peiHuoVO.setOrderProductIndex(rowIndex);
				//货品配货进度
				int progress  = (int) (Common_util.getFormatDouble((double)quantity/(double)orderProduct.getQuantity())*100);
				peiHuoVO.setProgress(progress);
				//单据配货数量
				long completeNums = inventoryOrderProductDAOImpl.selectCompleteNums(orderId);
				peiHuoVO.setCompleteNums((int)completeNums);
				//单据未配数量
				peiHuoVO.setNoNums(order.getTotalQuantity()-(int)completeNums);				
				double completeRate  = (double)completeNums/(double)order.getTotalQuantity();
				
				//单据配货进度
				peiHuoVO.setOrderProgress((int) (Common_util.getFormatDouble(completeRate)*100));
				
				peiHuoVO.setIsCheck(isCheck);
				response.setReturnValue(peiHuoVO);
				response.setSuccess("配货完成");
			}
		}
		return response;
	}


	
	/**
	 * 保存配货单据
	 * @param orderId
	 * @return
	 */
	@Transactional
	public Response updateInventoryOrder(int orderId,SessionInfo sessionInfo) {
		Response response = new Response();
		InventoryOrder order = inventoryOrderDAOImpl.get(orderId, true);
		if (order != null) {
			//验证权限
			UserInfor keepUser  = order.getOrder_Keeper();
			if (sessionInfo.getUserId() != keepUser.getUser_id()) {
				response.setFail("权限不足,此单据配货人员为："+keepUser.getUser_name());
				return response;
			}						

			order.setOrder_Status(InventoryOrder.STATUS_PEIHUO_COMPLETE);
			order.setOrder_PeiHuoComplTime(Common_util.getToday());
			inventoryOrderDAOImpl.update(order, true);	
			response.setSuccess("保存单据成功");
			}		
		return response;
	}

	
	/**
	 * 进入平板待配页面
	 * @param formBean
	 * @param loginUserInfor
	 * @throws ParseException 
	 */
	public void initIpadNoEquipped(IpadActionFormBean formBean,IpadActionUIBean uiBean,SessionInfo sessionInfo, int custRange) {
			UserInfor userInfor = userInforService.getUser(sessionInfo.getUserId(), true);
			
			List<Integer> custIds = inventoryOrderDAOImpl.getClientIdByRange(custRange);
			
			formBean.setUserInfor(userInfor);
			int custs = inventoryOrderDAOImpl.selectIpadNoEquidpped(custIds);
			formBean.setCusts(custs);
			int orderIds = inventoryOrderDAOImpl.selectIpadOrders(custIds);
			formBean.setOrderIds(orderIds);
			int snums = inventoryOrderDAOImpl.selectIpadNoEquidppedSnums(custIds);
			formBean.setSnums(snums);
	}
	
	/**
	 * 进入平板配货完成页面
	 * @param formBean
	 * @param uiBean
	 * @param sessionInfo
	 * @throws ParseException 
	 */
	public void initIpadAlread(IpadActionFormBean formBean, IpadActionUIBean uiBean, SessionInfo sessionInfo, int custRange) {
		UserInfor userInfor = userInforService.getUser(sessionInfo.getUserId(), true);
		formBean.setUserInfor(userInfor);
		
		List<Integer> custIds = inventoryOrderDAOImpl.getClientIdByRange(custRange);
		
		int completeCusts = inventoryOrderDAOImpl.selectIpadAlread(custIds);
		formBean.setCompleteCusts(completeCusts);
		int completeOrderIds = inventoryOrderDAOImpl.selectIpadAlreadOrders(custIds);
		formBean.setCompleteOrders(completeOrderIds);
		int nums = inventoryOrderProductDAOImpl.selectIpadEquidppedNums(custIds);
		formBean.setNums(nums);
	}

	/**
	 * 搜索配货单据
	 * @param formBean
	 * @param uiBean
	 * @param sessionInfo
	 */
	public void initIpadSearch(IpadActionFormBean formBean, IpadActionUIBean uiBean, SessionInfo sessionInfo) {
		UserInfor userInfor = userInforService.getUser(sessionInfo.getUserId(), true);
		formBean.setUserInfor(userInfor);

		formBean.setSearchStartTime(Common_util.getToday());
		formBean.setSearchEndTime(Common_util.getToday());
	}

	public Response listHeadqCust(IpadActionFormBean formBean) {
		Response response = new Response();
		List<HeadQCust> list = new ArrayList<HeadQCust>();
		if (!formBean.getCustName().equals("")) {
			list = headQCustDaoImpl.selectCusts(formBean.getCustName());
		}else {
			list = headQCustDaoImpl.selectCusts();
		}
				
		Map dataMap = new HashMap();
		dataMap.put("rows", list);

		response.setReturnValue(dataMap);
		response.setReturnCode(Response.SUCCESS);
		return response;
	}

		
	/**
	 * 根据条件查询配货单据
	 * @param formBean
	 * @return
	 * @throws ParseException 
	 */
	public Response searchPDAOrders4Peihuo(IpadActionFormBean formBean, int custRange) throws ParseException {
		Response response = new Response();

		
		List<InventoryOrder> list = inventoryOrderDAOImpl.searchPDAOrders(formBean.getSearchStartTime(), formBean.getSearchEndTime(), formBean.getClientId(),custRange);

		
		List<IpadPdaVO> vos = convertInventoryOrder2IpadPDAVO(list);
		
		Map dataMap = new HashMap();
		dataMap.put("rows", vos);

		response.setReturnValue(dataMap);
		response.setReturnCode(Response.SUCCESS);
		return response;
	}

	/**
	 * 待配详情或者配货完成单据回退主页
	 * @param formBean
	 * @param uiBean
	 * @param sessionInfo
	 * @return
	 * @throws ParseException 
	 */
	public boolean goBackHome(IpadActionFormBean formBean, IpadActionUIBean uiBean, SessionInfo sessionInfo, int custRange) throws ParseException {
		InventoryOrder order = inventoryOrderDAOImpl.get(formBean.getOrderId(), true);
		if (order != null) {
			if (order.getOrder_Status() == InventoryOrder.STATUS_PDA_COMPLETE || order.getOrder_Status() == InventoryOrder.STATUS_PEIHUO_INPROCESS) {
				initIpadNoEquipped(formBean,uiBean,sessionInfo, custRange);
				return true;
			}else if (order.getOrder_Status() == InventoryOrder.STATUS_PEIHUO_COMPLETE) {
				initIpadAlread(formBean,uiBean,sessionInfo,custRange);
				return false;
			}
		}
		return false;		
	}

	public List<InventoryOrderTagboxVO> initInventoryOrderStatus() {
		List<InventoryOrderTagboxVO> list = new ArrayList<InventoryOrderTagboxVO>();
		 Map<Integer, String> orderStatusMap = InventoryOrder.getOrderStatusMap();
		 if (orderStatusMap.size() != 0) {
			for (Integer key:orderStatusMap.keySet()) {
				InventoryOrderTagboxVO vo  = new InventoryOrderTagboxVO();
				vo.setId(Integer.toString(key));
				vo.setText(orderStatusMap.get(key));
				list.add(vo);
			}
		}				
		return list;
	}


}
